import { useState, useMemo, useEffect, useRef } from 'react'
import { useCategories } from '../contexts/CategoryContext.jsx'

// 内联输入行：用于"新增子节点"或"重命名"
function InlineInput({ defaultValue = '', placeholder, onSubmit, onCancel, depth = 0 }) {
  const ref = useRef(null)
  const [value, setValue] = useState(defaultValue)
  useEffect(() => { ref.current?.focus(); ref.current?.select() }, [])
  const submit = () => {
    const v = value.trim()
    if (!v) { onCancel(); return }
    onSubmit(v)
  }
  return (
    <div className="flex items-center gap-1 px-2 py-1" style={{ paddingLeft: 8 + depth * 14 }}>
      <input
        ref={ref}
        value={value}
        onChange={e => setValue(e.target.value)}
        placeholder={placeholder}
        className="flex-1 min-w-0 px-1.5 py-0.5 text-[13px] border border-brand-300 rounded outline-none focus:border-brand-500"
        onKeyDown={e => {
          if (e.key === 'Enter') submit()
          else if (e.key === 'Escape') onCancel()
        }}
      />
      <button onMouseDown={e => e.preventDefault()} onClick={submit} className="text-[11px] text-brand-600 hover:text-brand-800 px-1">✓</button>
      <button onMouseDown={e => e.preventDefault()} onClick={onCancel} className="text-[11px] text-gray-400 hover:text-gray-600 px-1">✕</button>
    </div>
  )
}

function TreeNode({
  node, depth, selectedId, onSelect,
  expandedMap, toggle,
  editingId, addingParentId,
  onStartEdit, onCancelEdit, onCommitEdit,
  onStartAdd, onCancelAdd, onCommitAdd,
  onDelete, matchedIds, searchActive
}) {
  const hasChildren = node.children && node.children.length > 0
  const expanded = !!expandedMap[node.id] || (searchActive && matchedIds.has(node.id))
  const active = selectedId === node.id
  const isEditing = editingId === node.id
  const isAdding = addingParentId === node.id

  const isMatched = !searchActive || matchedIds.has(node.id)
  if (!isMatched) return null

  return (
    <div>
      {isEditing ? (
        <InlineInput
          defaultValue={node.label}
          onSubmit={(v) => onCommitEdit(node.id, v)}
          onCancel={onCancelEdit}
          depth={depth}
        />
      ) : (
        <div
          onClick={() => {
            if (hasChildren) toggle(node.id)
            onSelect(node)
          }}
          className={[
            'group flex items-center gap-1.5 px-2 py-1.5 rounded-md cursor-pointer text-[13px] select-none',
            active ? 'bg-brand-50 text-brand-700 font-medium' : 'text-gray-700 hover:bg-gray-50'
          ].join(' ')}
          style={{ paddingLeft: 8 + depth * 14 }}
        >
          {hasChildren ? (
            <span className={`w-3 text-gray-400 transition-transform inline-block ${expanded ? 'rotate-90' : ''}`}>▸</span>
          ) : (
            <span className="w-3 text-gray-200">•</span>
          )}
          <span className="truncate flex-1">{node.label}</span>
          {/* hover 操作区 */}
          <span className={`${active ? 'opacity-100' : 'opacity-0'} group-hover:opacity-100 group-focus-within:opacity-100 flex items-center gap-0.5 text-gray-400`}>
            <button
              onClick={(e) => { e.stopPropagation(); onStartAdd(node.id) }}
              className="hover:text-brand-600 px-1 leading-none"
              title="新增子节点"
            >＋</button>
            <button
              onClick={(e) => { e.stopPropagation(); onStartEdit(node.id) }}
              className="hover:text-brand-600 px-1 leading-none"
              title="重命名"
            >✎</button>
            <button
              onClick={(e) => { e.stopPropagation(); onDelete(node) }}
              className="hover:text-rose-500 px-1 leading-none"
              title="删除"
            >×</button>
          </span>
        </div>
      )}
      {hasChildren && expanded && (
        <div>
          {node.children.map(child => (
            <TreeNode
              key={child.id}
              node={child}
              depth={depth + 1}
              selectedId={selectedId}
              onSelect={onSelect}
              expandedMap={expandedMap}
              toggle={toggle}
              editingId={editingId}
              addingParentId={addingParentId}
              onStartEdit={onStartEdit}
              onCancelEdit={onCancelEdit}
              onCommitEdit={onCommitEdit}
              onStartAdd={onStartAdd}
              onCancelAdd={onCancelAdd}
              onCommitAdd={onCommitAdd}
              onDelete={onDelete}
              matchedIds={matchedIds}
              searchActive={searchActive}
            />
          ))}
        </div>
      )}
      {isAdding && (
        <InlineInput
          placeholder="输入子节点名称，回车保存"
          onSubmit={(v) => onCommitAdd(node.id, v)}
          onCancel={onCancelAdd}
          depth={depth + 1}
        />
      )}
    </div>
  )
}

export default function CategoryTree({ selectedId, onSelect }) {
  const { tree, flat, total, loading, error, reload, addNode, updateNode, deleteNode } = useCategories()

  // 初次只展开 L1（数据量大，全展开会卡）
  // 以前走的是 useMemo([])，首次调用时 tree 可能还是空，导致永远拿不到默认展开项
  // 改成：tree 首次加载完成且用户还未手动操作过时，才设置默认展开
  const [expandedMap, setExpandedMap] = useState({})
  useEffect(() => {
    if (tree.length === 0) return
    setExpandedMap(prev => {
      // 用户已经手动展开/折叠过（expandedMap 不为空）则不覆盖
      if (Object.keys(prev).length > 0) return prev
      const map = {}
      tree.forEach(n => { map[n.id] = true })
      return map
    })
  }, [tree])

  const [editingId, setEditingId] = useState(null)
  const [addingParentId, setAddingParentId] = useState(null)
  const [addingRoot, setAddingRoot] = useState(false)
  const [keyword, setKeyword] = useState('')
  const [collapsed, setCollapsed] = useState(false)
  const [mutationError, setMutationError] = useState('')
  const [mutating, setMutating] = useState(false)

  const toggle = (id) => setExpandedMap(m => ({ ...m, [id]: !m[id] }))

  const collectAllIds = (nodes) => {
    const ids = []
    const walk = (arr) => arr.forEach(n => { ids.push(n.id); if (n.children?.length) walk(n.children) })
    walk(nodes)
    return ids
  }

  const expandAll = () => setExpandedMap(Object.fromEntries(collectAllIds(tree).map(id => [id, true])))
  const collapseAll = () => setExpandedMap(Object.fromEntries(collectAllIds(tree).map(id => [id, false])))

  // 搜索：返回匹配的节点 id 集合（含其所有祖先，便于父节点保留显示）
  const { matchedIds, searchActive } = useMemo(() => {
    const k = keyword.trim().toLowerCase()
    if (!k) return { matchedIds: new Set(), searchActive: false }
    const set = new Set()
    const idToNode = new Map(flat.map(n => [n.id, n]))
    flat.forEach(n => {
      if (n.label.toLowerCase().includes(k)) {
        // 加入自身和所有祖先
        let cur = n
        while (cur) {
          set.add(cur.id)
          cur = cur.parent_id != null ? idToNode.get(cur.parent_id) : null
        }
        // 加入所有子孙
        const queue = [n.id]
        while (queue.length) {
          const pid = queue.shift()
          flat.filter(x => x.parent_id === pid).forEach(c => { set.add(c.id); queue.push(c.id) })
        }
      }
    })
    return { matchedIds: set, searchActive: true }
  }, [keyword, flat])

  // 搜索激活时，自动展开所有匹配节点的祖先，避免隐藏在折叠节点中
  useEffect(() => {
    if (!searchActive || matchedIds.size === 0) return
    setExpandedMap(prev => {
      const next = { ...prev }
      matchedIds.forEach(id => { next[id] = true })
      return next
    })
  }, [searchActive, matchedIds])

  const handleStartEdit = (id) => { setMutationError(''); setEditingId(id); setAddingParentId(null); setAddingRoot(false) }
  const handleCancelEdit = () => setEditingId(null)
  const handleCommitEdit = async (id, label) => {
    setMutating(true)
    setMutationError('')
    const ok = await updateNode(id, label)
    setMutating(false)
    if (ok) setEditingId(null)
    else setMutationError('重命名失败，请检查权限或节点名称后重试。')
  }

  const handleStartAdd = (parentId) => {
    setMutationError('')
    setAddingParentId(parentId)
    setEditingId(null)
    setAddingRoot(false)
    // 自动展开父节点
    setExpandedMap(m => ({ ...m, [parentId]: true }))
  }
  const handleCancelAdd = () => setAddingParentId(null)
  const handleCommitAdd = async (parentId, label) => {
    setMutating(true)
    setMutationError('')
    const newNode = await addNode(parentId, label)
    setMutating(false)
    if (newNode) {
      setAddingParentId(null)
      setExpandedMap(m => ({ ...m, [parentId]: true }))
    } else {
      setMutationError('新增失败，请检查权限或是否存在同名节点。')
    }
  }

  const handleStartAddRoot = () => { setMutationError(''); setAddingRoot(true); setAddingParentId(null); setEditingId(null) }
  const handleCommitAddRoot = async (label) => {
    setMutating(true)
    setMutationError('')
    const newNode = await addNode(null, label)
    setMutating(false)
    if (newNode) setAddingRoot(false)
    else setMutationError('新增失败，请检查权限或是否存在同名节点。')
  }

  const handleDelete = async (node) => {
    const hasKids = node.children && node.children.length > 0
    const confirmMsg = hasKids
      ? `确定删除「${node.label}」及其全部子节点？此操作不可撤销。`
      : `确定删除「${node.label}」？`
    if (window.confirm(confirmMsg)) {
      setMutating(true)
      setMutationError('')
      const result = await deleteNode(node.id)
      setMutating(false)
      if (result) {
        if (selectedId === node.id) onSelect(null)
      } else {
        setMutationError('删除失败；节点下存在 Skill 时不能删除，请先迁移关联 Skill。')
      }
    }
  }

  // 折叠状态：只渲染一个细竖条 + 展开按钮
  if (collapsed) {
    return (
      <div className="w-9 h-full min-h-0 flex-shrink-0 bg-white border-r border-gray-200 flex flex-col items-center">
        <button
          onClick={() => setCollapsed(false)}
          className="w-full py-3 text-brand-600 hover:bg-brand-50 border-b border-gray-100"
          title="展开流程架构面板"
        >»</button>
        <div className="flex-1 flex items-center justify-center text-[12px] text-gray-500 select-none" style={{ writingMode: 'vertical-rl' }}>
          流程架构 · {total} 节点
        </div>
      </div>
    )
  }

  return (
    <div className="w-64 h-full min-h-0 flex-shrink-0 bg-white border-r border-gray-200 flex flex-col">
      {/* 顶部标题栏 */}
      <div className="px-3 py-3 flex items-center justify-between border-b border-gray-100">
        <div className="flex items-center gap-1.5 text-[13px] font-medium text-gray-800">
          <span className="text-brand-600">⇲</span>
          <span>流程架构</span>
          <span className="text-[11px] text-gray-400 font-normal">{total} 节点</span>
        </div>
        <div className="flex items-center gap-1 text-gray-400 text-[12px]">
          <button onClick={expandAll} className="hover:text-brand-600 px-1" title="展开全部">⤢</button>
          <button onClick={collapseAll} className="hover:text-brand-600 px-1" title="收起全部">⤡</button>
          <button onClick={() => setCollapsed(true)} className="hover:text-brand-600 px-1" title="收起面板">«</button>
        </div>
      </div>

      {/* 搜索 + 新增 L1 */}
      <div className="px-3 py-2 border-b border-gray-100 space-y-2">
        <input
          value={keyword}
          onChange={e => setKeyword(e.target.value)}
          placeholder="搜索节点..."
          className="w-full px-2 py-1 text-[12px] border border-gray-200 rounded focus:outline-none focus:border-brand-400"
        />
        {!addingRoot ? (
          <button
            onClick={handleStartAddRoot}
            className="w-full text-[12px] text-brand-600 border border-dashed border-brand-300 rounded py-1 hover:bg-brand-50"
          >
            ＋ 新增一级流程
          </button>
        ) : (
          <InlineInput
            placeholder="输入一级流程名称"
            onSubmit={handleCommitAddRoot}
            onCancel={() => setAddingRoot(false)}
            depth={0}
          />
        )}
        {mutationError && (
          <div role="alert" className="rounded bg-rose-50 px-2 py-1.5 text-[11px] leading-4 text-rose-600">
            {mutationError}
          </div>
        )}
        {mutating && <div className="text-[11px] text-gray-400">正在保存…</div>}
      </div>

      {/* 树主体 */}
      <div className="flex-1 min-h-0 overflow-y-auto overscroll-contain scrollbar-thin py-2">
        <div
          onClick={() => onSelect(null)}
          className={[
            'mx-2 mb-1 px-2 py-1.5 rounded-md cursor-pointer text-[13px]',
            selectedId == null ? 'bg-brand-50 text-brand-700 font-medium' : 'text-gray-700 hover:bg-gray-50'
          ].join(' ')}
        >
          全部
        </div>
        {loading && tree.length === 0 && (
          <div className="text-center text-[12px] text-gray-400 py-8">加载流程架构中…</div>
        )}
        {!loading && error && tree.length === 0 && (
          <div className="px-3 py-6 text-center">
            <div className="text-[12px] text-rose-500 mb-2">加载失败</div>
            <div className="text-[11px] text-gray-400 mb-3 break-all">{error}</div>
            <button
              onClick={() => reload()}
              className="text-[12px] text-brand-600 border border-brand-300 rounded px-3 py-1 hover:bg-brand-50"
            >重新加载</button>
          </div>
        )}
        {tree.map(n => (
          <TreeNode
            key={n.id}
            node={n}
            depth={0}
            selectedId={selectedId}
            onSelect={onSelect}
            expandedMap={expandedMap}
            toggle={toggle}
            editingId={editingId}
            addingParentId={addingParentId}
            onStartEdit={handleStartEdit}
            onCancelEdit={handleCancelEdit}
            onCommitEdit={handleCommitEdit}
            onStartAdd={handleStartAdd}
            onCancelAdd={handleCancelAdd}
            onCommitAdd={handleCommitAdd}
            onDelete={handleDelete}
            matchedIds={matchedIds}
            searchActive={searchActive}
          />
        ))}
        {!loading && !error && tree.length === 0 && (
          <div className="text-center text-[12px] text-gray-400 py-8">暂无节点，点击上方“新增一级流程”创建</div>
        )}
      </div>
    </div>
  )
}
