import { useCallback, useEffect, useMemo, useState } from 'react'
import { useLocation, useNavigate, useParams } from 'react-router-dom'
import { api, ApiError } from '../api/client'
import { ExpandGraphJobPanel } from '../components/ExpandGraphJobPanel'
import { PlacementScanJobPanel } from '../components/PlacementScanJobPanel'
import { ResearchMapOverview } from '../components/ResearchMapOverview'
import { rememberTopicId } from '../lib/brandContext'
import {
  patrolTagContextFromPlacementTopic,
  resolvePatrolKeywords,
  savedPatrolKeywords,
  type ExpandKnowledgeGraphData,
  type KnowledgeGraphData,
} from '../lib/knowledgeGraph'
import { placementFlowPath } from '../lib/placementFlow'
import {
  activeExpandJobHint,
  expandGraphActionLabel,
  expandJobTerminalMessage,
  formatActiveJobConflictError,
  isActiveJobStatus,
  isTerminalJobStatus,
} from '../lib/jobStatus'
import { topicResearchMapPath, topicSettingsPath, topicTitle } from '../lib/placementTopics'
import type { ResearchMapDraft } from '../components/ResearchMapEditor'
import { hasResearchMap } from '../lib/placementTopics'
import type { BrandData } from '../types/brand'
import type { PlacementTopicData } from '../types/placementTopic'
import type { JobData } from '../types/api'
import { AcLink, Button, Card, ErrorText, Notice, PageTitle, SuccessText } from '../components/ui'

type LocationState = {
  expandJobId?: string
}

export function PlacementTopicResearchMapPage() {
  const navigate = useNavigate()
  const location = useLocation()
  const { id = '' } = useParams()
  const [topic, setTopic] = useState<PlacementTopicData | null>(null)
  const [catalogBrand, setCatalogBrand] = useState<BrandData | null>(null)
  const [graph, setGraph] = useState<KnowledgeGraphData | null>(null)
  const [expandJob, setExpandJob] = useState<JobData | null>(null)
  const [expandJobId, setExpandJobId] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)
  const [expanding, setExpanding] = useState(false)
  const [scanJob, setScanJob] = useState<JobData | null>(null)
  const [scanJobId, setScanJobId] = useState<string | null>(null)
  const [scanning, setScanning] = useState(false)
  const [error, setError] = useState('')
  const [message, setMessage] = useState('')

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

  const reloadTopic = useCallback(async () => {
    if (!id) return null
    const topicRes = await api.get<PlacementTopicData>(`/api/v1/placement/topics/${encodeURIComponent(id)}`, { auth: true })
    const brandRes = await api.get<BrandData>(
      `/api/v1/brands/${encodeURIComponent(topicRes.brand_id)}`,
      { auth: true },
    )
    setTopic(topicRes)
    setCatalogBrand(brandRes)
    await reloadGraph().catch(() => null)
    return topicRes
  }, [id, reloadGraph])

  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: 'placement_topic', scope_id: id },
    })
    const activeExpand = (data.list ?? []).find(
      (job) => job.template_type === 'expand-graph' && isActiveJobStatus(job.status),
    )
    const activeScan = (data.list ?? []).find(
      (job) => job.template_type === 'placement-scan' && isActiveJobStatus(job.status),
    )
    setExpandJob(activeExpand ?? null)
    setExpandJobId(activeExpand?.id ?? null)
    setScanJob(activeScan ?? null)
    setScanJobId(activeScan?.id ?? null)
    if (activeExpand) {
      setMessage(activeExpandJobHint(activeExpand))
      setError('')
    }
  }, [id])

  const refreshExpandJob = useCallback(
    async (jobId: string) => {
      try {
        const job = await api.get<JobData>(`/api/v1/jobs/${encodeURIComponent(jobId)}`, { auth: true })
        if (isTerminalJobStatus(job.status)) {
          setExpandJob(null)
          setExpandJobId(null)
          const terminalMsg = expandJobTerminalMessage(job.status)
          if (job.status === 'succeeded') {
            await reloadTopic()
          }
          if (terminalMsg) {
            setMessage(terminalMsg)
            setError('')
          } else {
            setError(job.error?.trim() || job.progress?.summary || '研究地圖產生失敗')
            setMessage('')
          }
          return
        }
        setExpandJob(job)
        setExpandJobId(job.id)
        setMessage(activeExpandJobHint(job))
        setError('')
        await reloadTopic()
      } catch (e) {
        setExpandJob(null)
        setExpandJobId(null)
        setError(e instanceof ApiError ? e.message : '無法追蹤產生進度')
      }
    },
    [reloadTopic],
  )

  useEffect(() => {
    if (!id) return
    setLoading(true)
    setError('')
    Promise.all([reloadTopic(), loadActiveJobs()])
      .catch((e) => setError(e instanceof ApiError ? e.message : '載入失敗'))
      .finally(() => setLoading(false))
  }, [id, reloadTopic, loadActiveJobs])

  useEffect(() => {
    const state = location.state as LocationState | null
    if (state?.expandJobId) {
      setExpandJobId(state.expandJobId)
      navigate(topicResearchMapPath(id), { replace: true, state: null })
    }
  }, [id, location.state, navigate])

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

  const refreshScanJob = useCallback(
    async (jobId: string) => {
      try {
        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(job.progress?.summary || '海巡完成，可到獲客台查看貼文')
            setError('')
          } else {
            setError(job.error?.trim() || job.progress?.summary || '海巡失敗')
            setMessage('')
          }
          return
        }
        setScanJob(job)
        setScanJobId(job.id)
        setMessage(job.progress?.summary || '雙軌海巡進行中…')
        setError('')
      } catch (e) {
        setScanJob(null)
        setScanJobId(null)
        setError(e instanceof ApiError ? e.message : '無法追蹤海巡進度')
      }
    },
    [],
  )

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

  const saveResearchMap = useCallback(
    async (draft: ResearchMapDraft) => {
      if (!id) return
      const updated = await api.patch<PlacementTopicData>(
        `/api/v1/placement/topics/${encodeURIComponent(id)}`,
        {
          audience_summary: draft.audience_summary,
          content_goal: draft.content_goal,
          questions: draft.questions,
          pillars: draft.pillars,
          exclusions: draft.exclusions,
          patrol_keywords: draft.patrol_keywords,
        },
        { auth: true },
      )
      setTopic(updated)
      setMessage(
        savedPatrolKeywords(updated.research_map).length > 0
          ? `研究地圖已儲存（${savedPatrolKeywords(updated.research_map).length} 組海巡關鍵字）`
          : '研究地圖已儲存',
      )
      setError('')
    },
    [id],
  )

  const startPatrolScan = async () => {
    if (!id || loading || scanning || scanActive || jobActive) return
    const keywords = resolvePatrolKeywords(
      topic?.research_map,
      graph?.nodes ?? [],
      patrolTagContextFromPlacementTopic(topic, catalogBrand),
    )
    if (!keywords.length) {
      setError('請先完成研究地圖產生，系統會依受眾提問自動整理海巡關鍵字')
      setMessage('')
      return
    }
    setScanning(true)
    setError('')
    setMessage('正在建立海巡任務…')
    try {
      rememberTopicId(id)
      const data = await api.post<{ job_id: string; message?: string }>(
        `/api/v1/placement/topics/${encodeURIComponent(id)}/scan-jobs`,
        { dual_track: true, patrol_mode: true },
        { auth: true },
      )
      setMessage(data.message || `已用 ${keywords.length} 組關鍵字啟動雙軌海巡`)
      setScanJobId(data.job_id)
      await refreshScanJob(data.job_id)
    } catch (e) {
      const msg = e instanceof ApiError ? e.message : '啟動海巡失敗'
      setError(msg)
      setMessage('')
    } finally {
      setScanning(false)
    }
  }

  const expandMap = async () => {
    const seed = topic?.seed_query?.trim()
    if (!id || !seed) {
      setError('請先到主題設定填寫種子關鍵字')
      return
    }
    setExpanding(true)
    setError('')
    setMessage('')
    try {
      const job = await api.post<ExpandKnowledgeGraphData>(
        `/api/v1/placement/topics/${encodeURIComponent(id)}/knowledge-graph/expand`,
        { seed_query: seed, regenerate_map: true },
        { auth: true },
      )
      setExpandJobId(job.job_id)
      await refreshExpandJob(job.job_id)
      setMessage(job.message || '研究地圖產生中…')
    } catch (e) {
      const raw = e instanceof ApiError ? e.message : '產生研究地圖失敗'
      setError(formatActiveJobConflictError(raw))
      void loadActiveJobs().catch(() => undefined)
    } finally {
      setExpanding(false)
    }
  }

  if (!id) {
    return (
      <Card className="py-8 text-center">
        <p className="text-base text-muted">未指定主題。</p>
      </Card>
    )
  }

  const title = topic ? topicTitle(topic) : '研究地圖'
  const seedReady = !!topic?.seed_query?.trim()
  const jobActive = expanding || (expandJob != null && isActiveJobStatus(expandJob.status))
  const mapLoading =
    jobActive && expandJob?.status !== 'cancel_requested' && !hasResearchMap(topic) && !(graph?.nodes?.length)
  const actionLabel = expandGraphActionLabel(expandJob?.status, hasResearchMap(topic))
  const actionTitle =
    expandJob?.status === 'cancel_requested'
      ? '任務取消中，請稍候完成後再重新產生'
      : jobActive
        ? '研究地圖產生中，請稍候'
        : undefined
  const patrolContext = useMemo(
    () => patrolTagContextFromPlacementTopic(topic, catalogBrand),
    [topic, catalogBrand],
  )
  const patrolKeywords = useMemo(
    () => resolvePatrolKeywords(topic?.research_map, graph?.nodes ?? [], patrolContext),
    [topic?.research_map, graph?.nodes, patrolContext],
  )
  const scanActive = scanning || (scanJob != null && isActiveJobStatus(scanJob.status))
  const patrolBlockedReason =
    jobActive
      ? '研究地圖產生中，請稍候再海巡'
      : scanActive
        ? '海巡任務進行中'
        : patrolKeywords.length === 0
          ? '請先產生研究地圖（會自動整理海巡關鍵字）'
          : ''

  return (
    <div className="mx-auto w-full max-w-6xl space-y-6">
      <AcLink to="/placement/topics" className="inline-flex items-center gap-1.5 text-sm">
        ← 找 TA 主題
      </AcLink>

      <div className="flex flex-wrap items-start justify-between gap-4">
        <PageTitle title="研究地圖" subtitle={loading ? '載入中…' : `「${title}」的受眾方向與延伸知識。`} />
        <div className="hx-page-actions">
          <Button variant="ghost" onClick={() => navigate(topicSettingsPath(id))}>
            主題設定
          </Button>
          <Button
            variant="soft"
            onClick={() => void expandMap()}
            disabled={loading || jobActive || !seedReady}
            title={actionTitle}
          >
            {actionLabel}
          </Button>
          {hasResearchMap(topic) || graph?.nodes?.length ? (
            <Button
              onClick={() => void startPatrolScan()}
              disabled={loading || scanning || scanActive || jobActive}
              title={patrolBlockedReason || undefined}
            >
              {scanActive ? '海巡進行中…' : scanning ? '建立任務中…' : '開始海巡'}
            </Button>
          ) : null}
        </div>
      </div>

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

      {patrolBlockedReason && !loading && !scanning && !scanActive && !jobActive ? (
        <Notice tone="warning" title="還不能開始海巡" message={patrolBlockedReason} />
      ) : null}

      {!seedReady && !loading ? (
        <Card className="border-warning/30 bg-warning-soft/40">
          <p className="text-sm text-ink">
            尚未設定種子關鍵字。請到
            <button
              type="button"
              className="mx-1 font-semibold text-brand hover:underline"
              onClick={() => navigate(topicSettingsPath(id))}
            >
              主題設定
            </button>
            填寫並儲存後，再按「產生研究地圖」。
          </p>
        </Card>
      ) : null}

      {patrolKeywords.length > 0 ? (
        <Notice
          tone="info"
          title={`將海巡 ${patrolKeywords.length} 組搜尋短句`}
          message="會使用畫面上的優先海巡關鍵字；相關軌＋近期軌（7 天優先）。搜尋管道依帳號連線設定（API / Brave / 爬蟲）。"
        />
      ) : hasResearchMap(topic) ? (
        <Notice
          tone="warning"
          title="尚未設定海巡關鍵字"
          message="請按「編輯研究地圖」，填入你想回覆的 Threads 搜尋短句並儲存，再按「開始海巡」。"
        />
      ) : null}

      <div className="hx-research-map-workspace">
        {jobActive ? (
          <div className="mb-5">
            {expandJob ? (
              <ExpandGraphJobPanel job={expandJob} />
            ) : (
              <Card>
                <p className="text-sm text-ink-secondary">研究地圖產生中，正在建立背景任務…</p>
              </Card>
            )}
          </div>
        ) : null}
        {scanJob ? (
          <Card className="mb-5 space-y-4">
            <div className="flex flex-wrap items-center justify-between gap-3">
              <p className="text-sm font-bold text-ink">雙軌海巡進度</p>
              {scanJob.status === 'succeeded' ? (
                <AcLink
                  to={placementFlowPath('/outreach', id)}
                  className="ac-btn-secondary inline-flex min-h-10 items-center px-4 text-sm"
                >
                  前往獲客台 →
                </AcLink>
              ) : null}
            </div>
            <PlacementScanJobPanel job={scanJob} />
          </Card>
        ) : null}
        <ResearchMapOverview
          map={topic?.research_map}
          graph={graph}
          brand={topic}
          catalogBrand={catalogBrand}
          patrolKeywords={patrolKeywords}
          loading={loading || mapLoading}
          onSaveResearchMap={saveResearchMap}
        />
      </div>

    </div>
  )
}
