<script setup lang="ts">
import type { CategoryNode } from './CategoryTreeNode.vue'

export type CategoryFormMode = 'create' | 'rename' | 'cover' | 'delete' | 'move'

const props = defineProps<{
  mode: CategoryFormMode
  node: CategoryNode | null        // target node (null for top-level create)
  parentNode: CategoryNode | null   // parent for create-child
  categories: CategoryNode[]        // full tree for move-picker
  visible: boolean
}>()

const emit = defineEmits<{
  'update:visible': [v: boolean]
  submit: [data: { mode: CategoryFormMode; nodeId: string | null; name?: string; slug?: string; image?: string; targetParentId?: string | null }]
}>()

// ── Form state ──

const name = ref('')
const image = ref('')
const slugManual = ref('')
const slugTouched = ref(false)
const saving = ref(false)
const error = ref('')
const moveTargetId = ref<string | null>(null)

// ── Computed ──

const title = computed(() => {
  switch (props.mode) {
    case 'create': return props.parentNode ? `在「${props.parentNode.name}」下新建` : '新建分类'
    case 'rename': return '重命名分类'
    case 'cover': return '更换封面'
    case 'delete': return '删除分类'
    case 'move': return '移动到…'
    default: return ''
  }
})

const autoSlug = computed(() => {
  return name.value
    .trim()
    .toLowerCase()
    .replace(/\s+/g, '-')
    .replace(/[^a-z0-9-]/g, '')
    .slice(0, 100)
})

// Sync auto-slug to manual field if user hasn't touched it
watch(autoSlug, (val) => {
  if (!slugTouched.value && val) {
    slugManual.value = val
  }
})

function onSlugInput() {
  slugTouched.value = true
}

function fallbackSlug(): string {
  return `cat-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`
}

const effectiveSlug = computed(() => {
  return slugManual.value.trim() || autoSlug.value || fallbackSlug()
})

// Flatten tree for move picker
interface FlatOption { id: string; name: string; depth: number }
const flatOptions = computed<FlatOption[]>(() => {
  const result: FlatOption[] = [{ id: '', name: '（根目录）', depth: 0 }]
  function walk(nodes: CategoryNode[], depth: number) {
    for (const n of nodes) {
      if (n.id === '__uncategorized__') continue
      if (n.id === props.node?.id) continue // can't move to self
      result.push({ id: n.id, name: n.name, depth })
      if (n.children) walk(n.children, depth + 1)
    }
  }
  walk(props.categories, 1)
  return result
})

// ── Init ──

watch(() => props.visible, (v) => {
  if (!v) return
  error.value = ''
  saving.value = false
  moveTargetId.value = null

  slugManual.value = ''
  slugTouched.value = false

  switch (props.mode) {
    case 'create':
      name.value = ''
      image.value = ''
      break
    case 'rename':
      name.value = props.node?.name ?? ''
      image.value = ''
      break
    case 'cover':
      name.value = ''
      image.value = props.node?.image ?? ''
      break
    case 'delete':
      name.value = ''
      image.value = ''
      break
    case 'move':
      name.value = ''
      image.value = ''
      moveTargetId.value = props.node?.id ? findParentId(props.categories, props.node.id) : null
      break
  }
})

function findParentId(nodes: CategoryNode[], childId: string): string | null {
  for (const n of nodes) {
    if (n.children?.some(c => c.id === childId)) return n.id
    if (n.children) {
      const r = findParentId(n.children, childId)
      if (r) return r
    }
  }
  return null
}

// ── Submit ──

async function onSubmit() {
  error.value = ''

  switch (props.mode) {
    case 'create': {
      const n = name.value.trim()
      if (!n) { error.value = '请输入分类名称'; return }
      break
    }
    case 'rename': {
      const n = name.value.trim()
      if (!n) { error.value = '请输入分类名称'; return }
      break
    }
    case 'cover': {
      if (!image.value.trim()) { error.value = '请输入封面图片 URL'; return }
      break
    }
    case 'delete':
      break
    case 'move':
      break
  }

  saving.value = true
  try {
    emit('submit', {
      mode: props.mode,
      nodeId: props.node?.id ?? null,
      name: props.mode === 'create' || props.mode === 'rename' ? name.value.trim() : undefined,
      slug: props.mode === 'create' ? effectiveSlug.value : (props.mode === 'rename' ? effectiveSlug.value : undefined),
      image: props.mode === 'cover' ? image.value.trim() : undefined,
      targetParentId: props.mode === 'move' ? moveTargetId.value : (props.mode === 'create' ? (props.parentNode?.id ?? null) : undefined),
    })
  } finally {
    saving.value = false
  }
}

function close() {
  emit('update:visible', false)
}
</script>

<template>
  <BoDialog
    :show="visible"
    :mask-can-close="!saving"
    :style="{ width: '420px' }"
    @update:show="(v: boolean) => emit('update:visible', v)"
  >
    <div class="cat-modal">
      <!-- Header -->
      <div class="cat-modal-header">
        <h2 class="cat-modal-title">{{ title }}</h2>
        <button type="button" class="cat-modal-close" :disabled="saving" @click="close">
          <Icon name="lucide:x" />
        </button>
      </div>

      <!-- Body -->
      <div class="cat-modal-body">
        <div v-if="error" class="cat-error">{{ error }}</div>

        <!-- Create / Rename -->
        <template v-if="mode === 'create' || mode === 'rename'">
          <div class="cat-field">
            <label class="cat-label"><span class="cat-required">*</span> 名称</label>
            <input
              v-model="name"
              type="text"
              class="cat-input"
              placeholder="分类名称"
              :disabled="saving"
              autofocus
              @keyup.enter="onSubmit"
            />
          </div>
          <div class="cat-field">
            <label class="cat-label">标识（slug）</label>
            <input
              v-model="slugManual"
              type="text"
              class="cat-input"
              :class="{ 'cat-input-muted': !slugTouched && !!autoSlug }"
              placeholder="自动生成或手动输入"
              :disabled="saving"
              @input="onSlugInput"
            />
            <span class="cat-hint">
              <template v-if="!slugManual.trim() && !autoSlug">名称无法自动生成，将随机生成标识</template>
              <template v-else>用于 URL 路径，可手动修改</template>
            </span>
          </div>
        </template>

        <!-- Change Cover -->
        <template v-if="mode === 'cover'">
          <div class="cat-field">
            <label class="cat-label"><span class="cat-required">*</span> 封面图片 URL</label>
            <input
              v-model="image"
              type="url"
              class="cat-input"
              placeholder="https://..."
              :disabled="saving"
              autofocus
              @keyup.enter="onSubmit"
            />
          </div>
          <div v-if="image" class="cat-cover-preview">
            <img :src="image" alt="封面预览" @error="(e) => { (e.target as HTMLImageElement).style.display = 'none' }" />
          </div>
        </template>

        <!-- Delete -->
        <template v-if="mode === 'delete'">
          <div class="cat-delete-warn">
            <Icon name="lucide:triangle-alert" class="cat-delete-icon" />
            <p>确定要删除「<strong>{{ node?.name }}</strong>」吗？</p>
            <p v-if="node?.children?.length" class="cat-delete-sub">
              将同时删除其 {{ node.children.length }} 个子分类
            </p>
            <p class="cat-delete-sub">此操作不可撤销</p>
          </div>
        </template>

        <!-- Move -->
        <template v-if="mode === 'move'">
          <div class="cat-field">
            <label class="cat-label">
              将「{{ node?.name }}」移动到
            </label>
            <select v-model="moveTargetId" class="cat-select" :disabled="saving">
              <option
                v-for="opt in flatOptions"
                :key="opt.id"
                :value="opt.id"
              >
                {{ '\u00A0\u00A0'.repeat(opt.depth) }}{{ opt.name }}
              </option>
            </select>
          </div>
        </template>
      </div>

      <!-- Footer -->
      <div class="cat-modal-footer">
        <button type="button" class="cat-btn cat-btn-cancel" :disabled="saving" @click="close">
          取消
        </button>
        <button
          v-if="mode === 'delete'"
          type="button"
          class="cat-btn cat-btn-danger"
          :disabled="saving"
          @click="onSubmit"
        >
          {{ saving ? '删除中…' : '确认删除' }}
        </button>
        <button
          v-else
          type="button"
          class="cat-btn cat-btn-primary"
          :disabled="saving"
          @click="onSubmit"
        >
          {{ saving ? '保存中…' : (mode === 'create' ? '创建' : '保存') }}
        </button>
      </div>
    </div>
  </BoDialog>
</template>

<style scoped>
.cat-modal {
  display: flex;
  flex-direction: column;
  max-height: 70vh;
  background: var(--color-canvas, #faf9f5);
  border-radius: 12px;
  overflow: hidden;
}

/* ── Header ── */

.cat-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 24px 0;
}

.cat-modal-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  color: var(--color-ink);
  margin: 0;
}

.cat-modal-close {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  border-radius: 8px;
  color: var(--color-muted);
  cursor: pointer;
  flex-shrink: 0;
  transition: all 0.12s ease;
}

.cat-modal-close :deep(svg) {
  width: 18px;
  height: 18px;
}

.cat-modal-close:hover {
  background: var(--color-surface-soft);
  color: var(--color-ink);
}

/* ── Body ── */

.cat-modal-body {
  padding: 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  overflow-y: auto;
}

.cat-error {
  padding: 10px 14px;
  background: rgba(198, 69, 69, 0.08);
  color: var(--color-error, #c64545);
  border-radius: 8px;
  font-size: 13px;
  line-height: 1.4;
}

.cat-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.cat-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--color-body, #3d3d3a);
}

.cat-label-optional {
  font-weight: 400;
  color: var(--color-muted, #6c6a64);
}

.cat-required {
  color: var(--color-error, #c64545);
  font-weight: 600;
}

.cat-input,
.cat-select {
  width: 100%;
  height: 40px;
  padding: 0 14px;
  font-size: 14px;
  color: var(--color-ink);
  background: var(--color-canvas, #faf9f5);
  border: 1px solid var(--color-hairline);
  border-radius: 8px;
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.cat-input:focus,
.cat-select:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(204, 120, 92, 0.15);
}

.cat-input-muted {
  color: var(--color-muted);
  background: var(--color-surface-soft, #f5f0e8);
  cursor: default;
  user-select: none;
}

.cat-select {
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236c6a64' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 36px;
}

.cat-hint {
  font-size: 11px;
  color: var(--color-muted-soft);
  line-height: 1.3;
}

.cat-cover-preview {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 8px;
  overflow: hidden;
  background: var(--color-surface-soft);
  border: 1px solid var(--color-hairline);
}

.cat-cover-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ── Delete warn ── */

.cat-delete-warn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-align: center;
  padding: 8px 0;
}

.cat-delete-icon {
  width: 36px;
  height: 36px;
  color: var(--color-error, #c64545);
  opacity: 0.7;
  margin-bottom: 4px;
}

.cat-delete-warn p {
  margin: 0;
  font-size: 14px;
  color: var(--color-body);
  line-height: 1.5;
}

.cat-delete-sub {
  font-size: 12px !important;
  color: var(--color-muted) !important;
}

/* ── Footer ── */

.cat-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 16px 24px;
  border-top: 1px solid var(--color-hairline);
  background: var(--color-surface-soft);
}

.cat-btn {
  height: 40px;
  padding: 0 20px;
  font-size: 14px;
  font-weight: 500;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s ease;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.cat-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.cat-btn-cancel {
  color: var(--color-body);
  background: var(--color-canvas);
  border: 1px solid var(--color-hairline);
}

.cat-btn-cancel:hover:not(:disabled) {
  background: var(--color-surface-soft);
  border-color: var(--color-muted);
}

.cat-btn-primary {
  color: var(--color-on-primary, #fff);
  background: var(--color-primary);
  border: none;
}

.cat-btn-primary:hover:not(:disabled) {
  background: var(--color-primary-active, #b5654f);
}

.cat-btn-danger {
  color: #fff;
  background: var(--color-error, #c64545);
  border: none;
}

.cat-btn-danger:hover:not(:disabled) {
  background: #a83838;
}
</style>
