import { computed, ref, type Ref } from 'vue'
import type { MemoryGraphLink, MemoryGraphNode, MemoryVisualization } from '../api/request'

export const MAX_GRAPH_NODES = 40
export const MAX_FOCUS_NODES = 28

export type LinkKind = 'co_review' | 'status' | 'similar'
export type GraphViewMode = 'browse' | 'focus'

export const LINK_KIND_META: Record<
  LinkKind,
  { label: string; color: string; desc: string }
> = {
  co_review: { label: '同日练习', color: '#4f6ef7', desc: '同一天训练过的词' },
  status: { label: '同状态', color: '#94a3b8', desc: '学习状态相同' },
  similar: { label: '词形相近', color: '#f59e0b', desc: '英文拼写相近' },
}

function passesNodeFilter(
  n: MemoryGraphNode,
  statusFilter: string,
  search: string
): boolean {
  if (statusFilter && n.status !== statusFilter) return false
  const q = search.trim().toLowerCase()
  if (!q) return true
  return n.label.toLowerCase().includes(q) || n.zh.toLowerCase().includes(q)
}

export function buildFocusNodes(
  viz: MemoryVisualization,
  centerId: string,
  statusFilter: string,
  search: string,
  linkFilters: Record<LinkKind, boolean>
): MemoryGraphNode[] {
  const nodeMap = new Map(viz.graph.nodes.map((n) => [n.id, n]))
  const center = nodeMap.get(centerId)
  if (!center) return []

  const ids = new Set<string>([centerId])
  for (const l of viz.graph.links) {
    const kind = l.kind as LinkKind
    if (!linkFilters[kind]) continue
    if (l.source === centerId) ids.add(l.target)
    if (l.target === centerId) ids.add(l.source)
  }

  let nodes = [...ids]
    .map((id) => nodeMap.get(id)!)
    .filter(Boolean)
    .filter((n) => passesNodeFilter(n, statusFilter, search))

  if (!nodes.some((n) => n.id === centerId)) {
    nodes = [center, ...nodes]
  }

  if (nodes.length > MAX_FOCUS_NODES) {
    const centerNode = nodes.find((n) => n.id === centerId)!
    const rest = nodes
      .filter((n) => n.id !== centerId)
      .sort((a, b) => a.mastery - b.mastery)
      .slice(0, MAX_FOCUS_NODES - 1)
    nodes = [centerNode, ...rest]
  }

  return nodes
}

export function useGraphFilter(viz: Ref<MemoryVisualization | null>) {
  const graphStatusFilter = ref('')
  const graphSearch = ref('')
  const graphViewMode = ref<GraphViewMode>('browse')
  const focusCenterId = ref<string | null>(null)
  const linkFilters = ref<Record<LinkKind, boolean>>({
    co_review: true,
    status: true,
    similar: true,
  })

  function setFocusCenter(id: string) {
    focusCenterId.value = id
    graphViewMode.value = 'focus'
  }

  function exitFocusMode() {
    focusCenterId.value = null
    graphViewMode.value = 'browse'
  }

  const browseMatchedCount = computed(() => {
    if (!viz.value) return 0
    let nodes = viz.value.graph.nodes
    if (graphStatusFilter.value) {
      nodes = nodes.filter((n) => n.status === graphStatusFilter.value)
    }
    const q = graphSearch.value.trim().toLowerCase()
    if (q) {
      nodes = nodes.filter(
        (n) => n.label.toLowerCase().includes(q) || n.zh.toLowerCase().includes(q)
      )
    }
    return nodes.length
  })

  const browseNodes = computed((): MemoryGraphNode[] => {
    if (!viz.value) return []
    let nodes = [...viz.value.graph.nodes]
    if (graphStatusFilter.value) {
      nodes = nodes.filter((n) => n.status === graphStatusFilter.value)
    }
    const q = graphSearch.value.trim().toLowerCase()
    if (q) {
      nodes = nodes.filter(
        (n) => n.label.toLowerCase().includes(q) || n.zh.toLowerCase().includes(q)
      )
    }
    if (nodes.length <= MAX_GRAPH_NODES) return nodes

    return [...nodes]
      .sort((a, b) => {
        const rank = (s: string) =>
          s === 'weak' ? 0 : s === 'learning' ? 1 : s === 'new' ? 2 : 3
        const dr = rank(a.status) - rank(b.status)
        if (dr !== 0) return dr
        return a.mastery - b.mastery
      })
      .slice(0, MAX_GRAPH_NODES)
  })

  const filteredGraphNodes = computed((): MemoryGraphNode[] => {
    if (!viz.value) return []
    if (graphViewMode.value === 'focus' && focusCenterId.value) {
      return buildFocusNodes(
        viz.value,
        focusCenterId.value,
        graphStatusFilter.value,
        graphSearch.value,
        linkFilters.value
      )
    }
    return browseNodes.value
  })

  const graphTruncated = computed(
    () =>
      graphViewMode.value === 'browse' && browseMatchedCount.value > MAX_GRAPH_NODES
  )

  const filteredGraphLinks = computed((): MemoryGraphLink[] => {
    if (!viz.value) return []
    const ids = new Set(filteredGraphNodes.value.map((n) => n.id))
    return viz.value.graph.links.filter((l) => {
      const kind = l.kind as LinkKind
      if (!linkFilters.value[kind]) return false
      return ids.has(l.source) && ids.has(l.target)
    })
  })

  const graphStatsText = computed(() => {
    const n = filteredGraphNodes.value.length
    const e = filteredGraphLinks.value.length
    const total = viz.value?.graph.nodes.length ?? 0
    if (graphViewMode.value === 'focus' && focusCenterId.value) {
      const center = viz.value?.graph.nodes.find((x) => x.id === focusCenterId.value)
      const label = center ? `${center.label}` : '当前词'
      return `聚焦模式：以「${label}」为中心，显示 ${n} 个关联词、${e} 条连线`
    }
    let text = `浏览模式：${n} 个节点、${e} 条连线（全库 ${total} 词）`
    if (graphTruncated.value) {
      text += ` · 已优先展示易错/薄弱词（最多 ${MAX_GRAPH_NODES} 个）`
    }
    return text
  })

  function isNodeVisible(id: string) {
    return filteredGraphNodes.value.some((n) => n.id === id)
  }

  return {
    graphStatusFilter,
    graphSearch,
    graphViewMode,
    focusCenterId,
    linkFilters,
    filteredGraphNodes,
    filteredGraphLinks,
    graphTruncated,
    graphStatsText,
    isNodeVisible,
    setFocusCenter,
    exitFocusMode,
    LINK_KIND_META,
  }
}
