import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Link } from 'react-router-dom'
import { api, ApiError } from '../api/client'
import { ResearchHutArt } from '../components/PersonaIslandArt'
import { PlacementFlowNav } from '../components/PlacementFlowNav'
import { useActiveBrand } from '../hooks/useActiveBrand'
import { ExpandGraphJobPanel } from '../components/ExpandGraphJobPanel'
import { PersonaScanSchedulePanel } from '../components/PersonaScanSchedulePanel'
import { PlacementScanJobPanel } from '../components/PlacementScanJobPanel'
import { KnowledgeGraphPanel } from '../components/KnowledgeGraphPanel'

import {
  AcLink,
  Badge,
  Button,
  Card,
  ErrorText,
  Field,
  Input,
  Notice,
  SuccessText,
} from '../components/ui'
import { isTerminalJobStatus } from '../lib/jobStatus'
import { placementFlowPath } from '../lib/placementFlow'
import {
  PAIN_TAG_MINIMUM,
  type ExpandKnowledgeGraphData,
  type KnowledgeGraphData,
  type KnowledgeGraphNode,
} from '../lib/knowledgeGraph'
import { topicResearchMapPath } from '../lib/placementTopics'
import { useIslanderPage } from '../lib/islander'
import {
  bindResearchIslanderActions,
  ensureResearchActionHandlers,
  unbindResearchIslanderActions,
} from '../lib/islander/researchActions'
import type { JobData } from '../types/api'

ensureResearchActionHandlers()

export function PersonaResearchPage() {
  const { brandId: id, brand, brands, setBrandId, loading: brandLoading } = useActiveBrand()

  const [graph, setGraph] = useState<KnowledgeGraphData | null>(null)
  const [draftNodes, setDraftNodes] = useState<KnowledgeGraphNode[]>([])
  const [seedQuery, setSeedQuery] = useState('')
  const [expandJob, setExpandJob] = useState<JobData | null>(null)
  const [expandJobId, setExpandJobId] = useState<string | null>(null)
  const [scanJob, setScanJob] = useState<JobData | null>(null)
  const [scanJobId, setScanJobId] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)
  const [busy, setBusy] = useState<string | null>(null)
  const [error, setError] = useState('')
  const [message, setMessage] = useState('')
  const draftNodesRef = useRef<KnowledgeGraphNode[]>([])

  useIslanderPage({
    title: '海巡研究',
    purpose: '知識圖譜擴展、雙維度 tag 勾選與海巡準備',
    hints: [
      '種子詞可用產品領域關鍵字，例如「敏感肌」',
      '痛點候選建議 ≥8，不足時可補充擴展',
      '勾選節點後儲存，之後才能開始雙軌海巡（Phase 1）',
      'Brave API key 在設定頁，跟隨登入帳號',
    ],
    suggestions: [
      '幫我擴展圖譜',
      '痛點 tag 夠了嗎？',
      '要勾選哪些節點海巡？',
    ],
  })

  const selectedCount = useMemo(
    () => draftNodes.filter((node) => node.selected_for_scan).length,
    [draftNodes],
  )

  const setDraftNodesSynced = useCallback((nodes: KnowledgeGraphNode[]) => {
    draftNodesRef.current = nodes
    setDraftNodes(nodes)
  }, [])

  const setNodeSelected = useCallback(
    (nodeId: string, selected: boolean) => {
      const next = draftNodesRef.current.map((node) =>
        node.id === nodeId ? { ...node, selected_for_scan: selected } : node,
      )
      setDraftNodesSynced(next)
    },
    [setDraftNodesSynced],
  )

  const saveSelectionInternal = useCallback(async () => {
    const nodes = draftNodesRef.current
    if (!id || nodes.length === 0) {
      throw new Error('尚無圖譜節點可儲存')
    }
    const updates = nodes.map((node) => ({
      node_id: node.id,
      selected_for_scan: node.selected_for_scan,
    }))
    const data = await api.patch<KnowledgeGraphData>(
      `/api/v1/brands/${encodeURIComponent(id)}/knowledge-graph/nodes`,
      { updates },
      { auth: true },
    )
    setGraph(data)
    setDraftNodesSynced(data.nodes ?? [])
    return data
  }, [id, setDraftNodesSynced])

  useEffect(() => {
    if (!id) return
    bindResearchIslanderActions({
      brandId: id,
      getSeedQuery: () => seedQuery,
      getDraftNodes: () => draftNodesRef.current,
      toggleNode: setNodeSelected,
      saveSelection: () => saveSelectionInternal(),
      onExpandStarted: (jobId, msg) => {
        setExpandJobId(jobId)
        if (msg) setMessage(msg)
      },
      onScanStarted: (jobId, msg) => {
        setScanJobId(jobId)
        if (msg) setMessage(msg)
      },
    })
    return () => unbindResearchIslanderActions()
  }, [id, seedQuery, setNodeSelected, saveSelectionInternal])

  const loadGraph = useCallback(async () => {
    if (!id) return
    try {
      const data = await api.get<KnowledgeGraphData>(
        `/api/v1/brands/${encodeURIComponent(id)}/knowledge-graph`,
        { auth: true },
      )
      setGraph(data)
      setDraftNodesSynced(data.nodes ?? [])
      setSeedQuery((prev) => (prev.trim() ? prev : data.seed ?? prev))
      return data
    } catch (e) {
      if (e instanceof ApiError && /not found|找不到/i.test(e.message)) {
        setGraph(null)
        setDraftNodesSynced([])
        return null
      }
      throw e
    }
  }, [id, setDraftNodesSynced])

  const refreshExpandJob = useCallback(
    async (jobId: string) => {
      const job = await api.get<JobData>(`/api/v1/jobs/${encodeURIComponent(jobId)}`, { auth: true })
      if (isTerminalJobStatus(job.status)) {
        setExpandJob(null)
        setExpandJobId(null)
        if (job.status === 'succeeded') {
          await loadGraph()
          setMessage('知識圖譜擴展完成，請勾選要海巡的節點')
        } else {
          setError(job.error?.trim() || job.progress?.summary || '圖譜擴展失敗')
        }
        return
      }
      setExpandJob(job)
      setExpandJobId(job.id)
    },
    [loadGraph],
  )

  const loadActiveJobs = useCallback(async () => {
    if (!id) return
    const data = await api.get<{ list: JobData[] }>('/api/v1/jobs', {
      auth: true,
      query: { page: 1, pageSize: 20, scope: 'brand', scope_id: id },
    })
    const list = data.list ?? []
    const activeExpand = list.find(
      (job) => job.template_type === 'expand-graph' && !isTerminalJobStatus(job.status),
    )
    const activeScan = list.find(
      (job) => job.template_type === 'placement-scan' && !isTerminalJobStatus(job.status),
    )
    setExpandJob(activeExpand ?? null)
    setExpandJobId(activeExpand?.id ?? null)
    setScanJob(activeScan ?? null)
    setScanJobId(activeScan?.id ?? null)
  }, [id])

  const refreshScanJob = useCallback(
    async (jobId: string) => {
      const job = await api.get<JobData>(`/api/v1/jobs/${encodeURIComponent(jobId)}`, { auth: true })
      if (isTerminalJobStatus(job.status)) {
        setScanJob(null)
        setScanJobId(null)
        if (job.status === 'succeeded') {
          setMessage('雙軌海巡完成，可到獲客台查看貼文')
        } else {
          setError(job.error?.trim() || job.progress?.summary || '海巡失敗')
        }
        return
      }
      setScanJob(job)
      setScanJobId(job.id)
    },
    [],
  )

  useEffect(() => {
    if (!id) return
    setLoading(true)
    setError('')
    Promise.all([loadGraph(), loadActiveJobs()])
      .then(([graphData]) => {
        if (brand?.seed_query?.trim()) {
          setSeedQuery((prev) => (prev.trim() ? prev : brand.seed_query!.trim()))
        } else if (!graphData?.seed && brand?.product_brief?.trim()) {
          const firstLine = brand.product_brief.trim().split(/[\n，,]/)[0]?.trim()
          if (firstLine && firstLine.length <= 40) {
            setSeedQuery((prev) => (prev.trim() ? prev : firstLine))
          }
        }
      })
      .catch((e) => setError(e instanceof ApiError ? e.message : '載入研究頁失敗'))
      .finally(() => setLoading(false))
  }, [id, brand?.seed_query, brand?.product_brief, loadGraph, loadActiveJobs])

  useEffect(() => {
    if (!expandJobId) return
    const timer = window.setInterval(() => {
      refreshExpandJob(expandJobId).catch(() => undefined)
    }, 3000)
    return () => window.clearInterval(timer)
  }, [expandJobId, refreshExpandJob])

  useEffect(() => {
    if (!scanJobId) return
    const timer = window.setInterval(() => {
      refreshScanJob(scanJobId).catch(() => undefined)
    }, 3000)
    return () => window.clearInterval(timer)
  }, [scanJobId, refreshScanJob])

  const runExpand = async (supplemental: boolean) => {
    if (!id || !seedQuery.trim()) return
    setBusy(supplemental ? 'supplemental' : 'expand')
    setError('')
    setMessage('')
    try {
      const data = await api.post<ExpandKnowledgeGraphData>(
        `/api/v1/brands/${encodeURIComponent(id)}/knowledge-graph/expand`,
        { seed_query: seedQuery.trim(), supplemental },
        { auth: true },
      )
      setMessage(data.message ?? '圖譜擴展已在背景執行')
      setExpandJobId(data.job_id)
      await refreshExpandJob(data.job_id)
    } catch (e) {
      setError(e instanceof ApiError ? e.message : '觸發圖譜擴展失敗')
    } finally {
      setBusy(null)
    }
  }

  const toggleNode = (nodeId: string, selected: boolean) => {
    setNodeSelected(nodeId, selected)
  }

  const selectPainNodes = () => {
    const next = draftNodesRef.current.map((node) => ({
      ...node,
      selected_for_scan:
        node.node_kind === 'pain' ||
        node.node_kind === 'symptom' ||
        node.node_kind === 'cause',
    }))
    setDraftNodesSynced(next)
  }

  const clearSelection = () => {
    setDraftNodesSynced(draftNodesRef.current.map((node) => ({ ...node, selected_for_scan: false })))
  }

  const startScan = async () => {
    if (!id || selectedCount === 0) return
    setBusy('scan')
    setError('')
    setMessage('')
    try {
      const saved = await saveSelectionInternal()
      const data = await api.post<{ job_id: string; message?: string }>(
        `/api/v1/brands/${encodeURIComponent(id)}/scan-jobs`,
        { dual_track: true, graph_id: saved.id },
        { auth: true },
      )
      setMessage(data.message ?? '雙軌海巡已在背景執行')
      setScanJobId(data.job_id)
      await refreshScanJob(data.job_id)
    } catch (e) {
      setError(e instanceof ApiError ? e.message : '啟動海巡失敗')
    } finally {
      setBusy(null)
    }
  }

  const saveSelection = async () => {
    if (!id || draftNodes.length === 0) return
    setBusy('save')
    setError('')
    setMessage('')
    try {
      await saveSelectionInternal()
      setMessage(`已儲存 ${selectedCount} 個勾選節點`)
    } catch (e) {
      setError(e instanceof ApiError ? e.message : '儲存勾選失敗')
    } finally {
      setBusy(null)
    }
  }

  if (!brandLoading && !id) {
    return (
      <div className="ac-persona-page space-y-8">
        <PlacementFlowNav
          active="research"
          brandId=""
          brands={brands}
          onBrandChange={setBrandId}
          brandLoading={brandLoading}
        />
        <Card>
          <p className="text-sm text-ink-secondary">
            請先在
            <Link to="/placement/topics" className="mx-1 font-semibold text-brand hover:underline">
              找 TA 主題
            </Link>
            新增主題並產生研究地圖，再開始海巡研究。
          </p>
        </Card>
      </div>
    )
  }

  const painTagCount = graph?.pain_tag_count ?? 0
  const displayName = brand?.display_name?.trim() || '未命名品牌'

  return (
    <div className="ac-persona-page space-y-8">
      <PlacementFlowNav
        active="research"
        brandId={id}
        brands={brands}
        onBrandChange={setBrandId}
        brandLoading={brandLoading}
      />

      <header className="ac-persona-research relative overflow-hidden rounded-[var(--radius-lg)] border-2 border-wood/40 bg-surface p-6">
        <ResearchHutArt className="ac-persona-research__art" />
        <div className="relative z-[1] space-y-3">
          <p className="display-en text-[10px] font-bold tracking-[0.16em] text-brand uppercase">
            Placement Research
          </p>
          <h1 className="text-2xl font-black text-ink">海巡研究 · {displayName}</h1>
          <p className="max-w-2xl text-sm leading-relaxed text-ink-secondary">
            依研究地圖勾選要海巡的節點，再進行雙軌掃描（7 天優先 / 30 天補充）。
          </p>
          <div className="flex flex-wrap gap-2">
            <Badge tone="sky">北極星：productFitScore</Badge>
            {graph ? <Badge tone="success">圖譜已建立</Badge> : <Badge tone="warning">圖譜待建立</Badge>}
          </div>
        </div>
      </header>

      {id ? (
        <section className="ac-persona-zone">
          <AcLink
            to={topicResearchMapPath(id)}
            className="ac-btn-secondary inline-flex min-h-11 items-center px-5 text-base"
          >
            查看研究地圖（受眾方向 · 延伸知識）→
          </AcLink>
        </section>
      ) : null}

      <section className="ac-persona-zone space-y-4">
        <Field
          label="種子詞"
          hint="產品或受眾領域關鍵字，例如「敏感肌」「新手爸媽保養」"
        >
          <Input
            value={seedQuery}
            onChange={(e) => setSeedQuery(e.target.value)}
            placeholder="輸入種子詞"
            disabled={loading || !!expandJob}
            data-islander-label="種子詞"
          />
        </Field>

        <div className="flex flex-wrap gap-2">
          <Button
            onClick={() => void runExpand(false)}
            disabled={busy === 'expand' || !!expandJob || !seedQuery.trim() || loading}
            data-islander-label="擴展圖譜"
          >
            {expandJob ? '擴展進行中…' : busy === 'expand' ? '建立任務中…' : '擴展圖譜（海巡用）'}
          </Button>
          {graph && painTagCount < PAIN_TAG_MINIMUM ? (
            <Button
              variant="soft"
              onClick={() => void runExpand(true)}
              disabled={busy === 'supplemental' || !!expandJob || !seedQuery.trim()}
              data-islander-label="補充擴展"
            >
              {busy === 'supplemental' ? '補充中…' : '補充擴展（痛點不足時）'}
            </Button>
          ) : null}
          <Link to="/settings" className="ac-btn-secondary inline-flex min-h-11 items-center px-5 text-base">
            研究設定
          </Link>
        </div>

        {expandJob ? (
          <div className="ac-island-card p-5">
            <p className="mb-3 text-xs font-bold text-brand">可自由切換頁面，任務不會中斷</p>
            <ExpandGraphJobPanel job={expandJob} />
            {expandJob.status === 'queued' || expandJob.status === 'waiting_worker' ? (
              <div className="mt-4">
                <Notice
                  tone="warning"
                  title="任務尚未被 Worker 接手"
                  message="請確認已執行 make node-worker 或對應的 go worker，且 API 在 :8890 運行。"
                />
              </div>
            ) : null}
          </div>
        ) : null}
      </section>

      <section>
        <h2 className="ac-section-title mb-4">海巡 tag 勾選</h2>
        <KnowledgeGraphPanel
          nodes={draftNodes}
          painTagCount={painTagCount}
          seed={graph?.seed ?? seedQuery}
          loading={loading}
          saving={busy === 'save'}
          onToggle={toggleNode}
          onSelectPainNodes={selectPainNodes}
          onClearSelection={clearSelection}
          onSaveSelection={() => void saveSelection()}
        />
      </section>

      {selectedCount > 0 ? (
        <section className="ac-persona-panel space-y-3">
          <h2 className="text-sm font-bold text-ink">下一步：雙軌海巡</h2>
          <p className="text-sm leading-relaxed text-ink-secondary">
            已勾選 {selectedCount} 個節點。每個 tag 會跑相關軌 + 近期軌（7 天優先，不足補 30 天）。
          </p>
          <div className="flex flex-wrap gap-2">
            <Button
              onClick={() => void startScan()}
              disabled={busy === 'scan' || !!scanJob || !graph}
              data-islander-label="開始雙軌海巡"
            >
              {scanJob ? '海巡進行中…' : busy === 'scan' ? '建立任務中…' : '開始雙軌海巡'}
            </Button>
            <AcLink
              to={placementFlowPath('/outreach', id, 'brand')}
              className="ac-btn-secondary inline-flex min-h-11 items-center px-5 text-sm"
            >
              前往獲客台 →
            </AcLink>
          </div>
          {scanJob ? (
            <div className="ac-island-card p-5">
              <PlacementScanJobPanel job={scanJob} />
            </div>
          ) : null}
        </section>
      ) : null}

      {graph ? (
        <section>
          <h2 className="ac-section-title mb-4">定期海巡</h2>
          <PersonaScanSchedulePanel brandId={id} selectedNodeCount={selectedCount} />
        </section>
      ) : null}

      <ErrorText message={error} />
      <SuccessText message={message} />
    </div>
  )
}