import { createContext, useContext, useEffect, useMemo, useState, useCallback } from 'react'
import { listCategoriesFlat, createCategory, updateCategory, deleteCategory } from '../services/api.js'

const CategoryContext = createContext(null)

/**
 * 把 cf-worker 节点（id/parent_id/code/name/level/path/status/sort）
 * 映射成前端旧组件期望的 shape（label/parent_id/sort_order/...）
 * 同时保留原字段供新组件使用（status / path / level）
 */
function adaptNode(n) {
  return {
    id:          n.id,                 // 字符串 'cat_xxx'
    parent_id:   n.parent_id || null,  // 字符串 或 null
    label:       n.name,
    sort_order:  n.sort ?? 0,
    node_key:    n.id,
    description: '',
    code:        n.code || '',
    level:       n.level,
    path:        n.path,
    status:      n.status || 'active',
  }
}

function flatToTree(flat) {
  const map = new Map()
  flat.forEach(n => map.set(n.id, { ...n, children: [] }))
  const roots = []
  flat.forEach(n => {
    const node = map.get(n.id)
    if (n.parent_id == null) roots.push(node)
    else {
      const p = map.get(n.parent_id)
      if (p) p.children.push(node); else roots.push(node)
    }
  })
  const sortRec = (arr) => {
    arr.sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0))
    arr.forEach(n => n.children && sortRec(n.children))
  }
  sortRec(roots)
  return roots
}

function mutationMessage(err, fallback) {
  return err?.friendlyMessage || err?.response?.data?.message || err?.response?.data?.error || fallback
}

export function CategoryProvider({ children }) {
  const [flat, setFlat] = useState([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState('')

  // 带重试的加载：网络抖动/冷启动握手慢等瞬时失败时自动重试，避免一次失败永久空白
  const reload = useCallback(async () => {
    setLoading(true); setError('')
    const maxAttempts = 4
    let lastErr = null
    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
      try {
        const r = await listCategoriesFlat()
        const data = r?.data || []
        // 拿到空数组也认为是异常（生产数据应有 315 节点），继续重试
        if (!Array.isArray(data) || data.length === 0) {
          lastErr = new Error('categories empty')
        } else {
          setFlat(data.map(adaptNode))
          setError('')
          setLoading(false)
          return true
        }
      } catch (e) {
        lastErr = e
        console.warn(`[categories] 第 ${attempt}/${maxAttempts} 次加载失败:`, e?.message || e)
      }
      if (attempt < maxAttempts) {
        // 指数退避：800ms / 1.6s / 3.2s
        await new Promise(res => setTimeout(res, 800 * Math.pow(2, attempt - 1)))
      }
    }
    console.error('加载流程架构最终失败:', lastErr)
    setError(lastErr?.message || '加载流程架构失败')
    setLoading(false)
    return false
  }, [])

  // reload 是 useCallback([])、引用稳定；依赖设为 [] 明确只初始拉一次，避免嵌套重复请求
  // eslint-disable-next-line react-hooks/exhaustive-deps
  useEffect(() => { reload() }, [])

  // 登录态变化时重新拉取（多标签页登录 / 当前标签页登录后强制刷新分类）
  useEffect(() => {
    const onStorage = (e) => {
      if (e.key === 'aipro_auth_user_v1' && e.newValue) reload()
    }
    const onAuthChange = () => reload()
    window.addEventListener('storage', onStorage)
    window.addEventListener('aipro:auth-changed', onAuthChange)
    return () => {
      window.removeEventListener('storage', onStorage)
      window.removeEventListener('aipro:auth-changed', onAuthChange)
    }
  }, [reload])

  const tree = useMemo(() => flatToTree(flat), [flat])
  const total = flat.length

  // 创建节点：parentId 为 null 则为根节点
  const addNode = useCallback(async (parentId, name) => {
    try {
      const res = await createCategory({ name, parent_id: parentId || null })
      await reload()
      return res?.data || res
    } catch (err) {
      alert(mutationMessage(err, '新增节点失败'))
      console.error('[addNode]', err)
      return null
    }
  }, [reload])

  // 更新节点名称
  const updateNode = useCallback(async (id, name) => {
    try {
      await updateCategory(id, { name })
      await reload()
      return true
    } catch (err) {
      alert(mutationMessage(err, '重命名节点失败'))
      console.error('[updateNode]', err)
      return false
    }
  }, [reload])

  // 删除节点（后端会级联删除子孙；有 skill 关联则 409）
  const deleteNode = useCallback(async (id) => {
    try {
      const res = await deleteCategory(id)
      await reload()
      return res
    } catch (err) {
      if (err?.response?.status === 409) {
        alert(mutationMessage(err, '该节点下有关联的 Skill，无法删除'))
      } else {
        alert(mutationMessage(err, '删除节点失败'))
      }
      console.error('[deleteNode]', err)
      return null
    }
  }, [reload])

  const value = {
    tree,
    flat,
    total,
    loading,
    error,
    reload,
    addNode,
    updateNode,
    deleteNode,
  }

  return <CategoryContext.Provider value={value}>{children}</CategoryContext.Provider>
}

export function useCategories() {
  const ctx = useContext(CategoryContext)
  if (!ctx) throw new Error('useCategories must be used within CategoryProvider')
  return ctx
}
