import { ArrowLeftRight, History, RefreshCcw, RotateCcw } from 'lucide-react'
import { startTransition, useCallback, useEffect, useMemo, useState } from 'react'
import { toast } from 'sonner'

import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Select } from '@/components/ui/select'
import { Skeleton } from '@/components/ui/skeleton'
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table'
import { Textarea } from '@/components/ui/textarea'
import { adminApi, ApiError } from '@/lib/api'
import { countLineDiff } from '@/lib/markdown-diff'
import { parseMarkdownDocument } from '@/lib/markdown-document'
import type { PostRevisionDetail, PostRevisionRecord } from '@/lib/types'

type RestoreMode = 'full' | 'markdown' | 'metadata'

const META_LABELS: Record<string, string> = {
  title: '标题',
  slug: 'Slug',
  description: '摘要',
  category: '分类',
  postType: '类型',
  image: '封面',
  images: '图片集',
  pinned: '置顶',
  status: '状态',
  visibility: '可见性',
  publishAt: '定时发布',
  unpublishAt: '下线时间',
  canonicalUrl: 'Canonical',
  noindex: 'Noindex',
  ogImage: 'OG 图',
  redirectFrom: '旧地址',
  redirectTo: '重定向',
  tags: '标签',
}

function stableValue(value: unknown) {
  if (Array.isArray(value) || (value && typeof value === 'object')) {
    return JSON.stringify(value)
  }
  return String(value ?? '')
}

function summarizeMetadataChanges(leftMarkdown: string, rightMarkdown: string) {
  const left = parseMarkdownDocument(leftMarkdown).meta
  const right = parseMarkdownDocument(rightMarkdown).meta

  return Object.entries(META_LABELS)
    .filter(([key]) => stableValue(left[key as keyof typeof left]) !== stableValue(right[key as keyof typeof right]))
    .map(([, label]) => label)
}

export function RevisionsPage() {
  const [revisions, setRevisions] = useState<PostRevisionRecord[]>([])
  const [selected, setSelected] = useState<PostRevisionDetail | null>(null)
  const [detailsCache, setDetailsCache] = useState<Record<number, PostRevisionDetail>>({})
  const [liveMarkdown, setLiveMarkdown] = useState('')
  const [loading, setLoading] = useState(true)
  const [refreshing, setRefreshing] = useState(false)
  const [restoring, setRestoring] = useState<string | null>(null)
  const [slugFilter, setSlugFilter] = useState('')
  const [compareTarget, setCompareTarget] = useState('current')

  const loadRevisions = useCallback(async (showToast = false) => {
    try {
      if (showToast) {
        setRefreshing(true)
      }

      const next = await adminApi.listPostRevisions({
        slug: slugFilter.trim() || undefined,
        limit: 120,
      })
      startTransition(() => {
        setRevisions(next)
      })
      if (showToast) {
        toast.success('版本历史已刷新。')
      }
    } catch (error) {
      if (error instanceof ApiError && error.status === 401) {
        return
      }
      toast.error(error instanceof ApiError ? error.message : '无法加载版本历史。')
    } finally {
      setLoading(false)
      setRefreshing(false)
    }
  }, [slugFilter])

  useEffect(() => {
    void loadRevisions(false)
  }, [loadRevisions])

  const openDetail = useCallback(async (id: number) => {
    try {
      const detail = detailsCache[id] ?? (await adminApi.getPostRevision(id))
      let liveMarkdownValue = ''
      try {
        const live = await adminApi.getPostMarkdown(detail.item.post_slug)
        liveMarkdownValue = live.markdown
      } catch {
        liveMarkdownValue = ''
      }
      startTransition(() => {
        setDetailsCache((current) => ({ ...current, [id]: detail }))
        setSelected(detail)
        setLiveMarkdown(liveMarkdownValue)
        setCompareTarget('current')
      })
    } catch (error) {
      toast.error(error instanceof ApiError ? error.message : '无法加载该版本详情。')
    }
  }, [detailsCache])

  useEffect(() => {
    if (!selected) {
      return
    }

    if (compareTarget === 'current' || !compareTarget) {
      return
    }

    const revisionId = Number(compareTarget)
    if (!Number.isFinite(revisionId) || detailsCache[revisionId]) {
      return
    }

    void adminApi
      .getPostRevision(revisionId)
      .then((detail) => {
        startTransition(() => {
          setDetailsCache((current) => ({ ...current, [revisionId]: detail }))
        })
      })
      .catch((error) => {
        toast.error(error instanceof ApiError ? error.message : '无法加载比较版本。')
      })
  }, [compareTarget, detailsCache, selected])

  const summary = useMemo(() => {
    const uniqueSlugs = new Set(revisions.map((item) => item.post_slug))
    return {
      count: revisions.length,
      slugs: uniqueSlugs.size,
    }
  }, [revisions])

  const compareCandidates = useMemo(
    () =>
      selected
        ? revisions.filter((item) => item.post_slug === selected.item.post_slug && item.id !== selected.item.id)
        : [],
    [revisions, selected],
  )

  const comparisonMarkdown = useMemo(() => {
    if (!selected) {
      return ''
    }

    if (compareTarget === 'current') {
      return liveMarkdown
    }

    const revisionId = Number(compareTarget)
    return Number.isFinite(revisionId) ? detailsCache[revisionId]?.markdown ?? '' : ''
  }, [compareTarget, detailsCache, liveMarkdown, selected])

  const comparisonLabel = useMemo(() => {
    if (compareTarget === 'current') {
      return '当前线上版本'
    }

    const revisionId = Number(compareTarget)
    const detail = Number.isFinite(revisionId) ? detailsCache[revisionId] : undefined
    return detail ? `版本 #${detail.item.id}` : '比较版本'
  }, [compareTarget, detailsCache])

  const diffStats = useMemo(() => {
    if (!selected || !comparisonMarkdown) {
      return { additions: 0, deletions: 0 }
    }
    return countLineDiff(comparisonMarkdown, selected.markdown ?? '')
  }, [comparisonMarkdown, selected])

  const metadataChanges = useMemo(() => {
    if (!selected || !comparisonMarkdown) {
      return [] as string[]
    }
    return summarizeMetadataChanges(comparisonMarkdown, selected.markdown ?? '')
  }, [comparisonMarkdown, selected])

  const runRestore = useCallback(
    async (mode: RestoreMode) => {
      if (!selected) {
        return
      }

      try {
        setRestoring(`${selected.item.id}:${mode}`)
        await adminApi.restorePostRevision(selected.item.id, mode)
        toast.success(`已按 ${mode} 模式回滚到版本 #${selected.item.id}`)
        await loadRevisions(false)
        await openDetail(selected.item.id)
      } catch (error) {
        toast.error(error instanceof ApiError ? error.message : '恢复版本失败。')
      } finally {
        setRestoring(null)
      }
    },
    [loadRevisions, openDetail, selected],
  )

  if (loading) {
    return (
      <div className="space-y-6">
        <Skeleton className="h-32 rounded-3xl" />
        <Skeleton className="h-[580px] rounded-3xl" />
      </div>
    )
  }

  return (
    <div className="space-y-6">
      <div className="flex flex-col gap-4 xl:flex-row xl:items-end xl:justify-between">
        <div className="space-y-3">
          <Badge variant="secondary">版本历史</Badge>
          <div>
            <h2 className="text-3xl font-semibold tracking-tight">文章版本快照、Diff 与局部回滚</h2>
            <p className="mt-2 max-w-3xl text-sm leading-7 text-muted-foreground">
              每次保存、导入、删除、恢复前后都会留下一份 Markdown 快照。现在支持比较当前线上版本或任意历史版本，并可选择 full / markdown / metadata 三种恢复模式。
            </p>
          </div>
        </div>

        <div className="flex flex-wrap items-center gap-3">
          <Input
            data-testid="revisions-slug-filter"
            value={slugFilter}
            onChange={(event) => setSlugFilter(event.target.value)}
            placeholder="按 slug 过滤，例如 hello-world"
            className="w-[280px]"
          />
          <Button variant="secondary" onClick={() => void loadRevisions(true)} disabled={refreshing}>
            <RefreshCcw className="h-4 w-4" />
            {refreshing ? '刷新中...' : '刷新'}
          </Button>
        </div>
      </div>

      <div className="grid gap-6 xl:grid-cols-[1.12fr_0.88fr]">
        <Card>
          <CardHeader className="flex flex-row items-start justify-between gap-4">
            <div>
              <CardTitle>快照列表</CardTitle>
              <CardDescription>
                当前共 {summary.count} 条快照，覆盖 {summary.slugs} 篇文章。
              </CardDescription>
            </div>
            <Badge variant="outline">{summary.count}</Badge>
          </CardHeader>
          <CardContent>
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>文章</TableHead>
                  <TableHead>操作</TableHead>
                  <TableHead>操作者</TableHead>
                  <TableHead>时间</TableHead>
                  <TableHead className="text-right">操作</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {revisions.map((item) => (
                  <TableRow key={item.id}>
                    <TableCell>
                      <div className="space-y-1">
                        <div className="font-medium">{item.post_title ?? item.post_slug}</div>
                        <div className="font-mono text-xs text-muted-foreground">{item.post_slug}</div>
                      </div>
                    </TableCell>
                    <TableCell>
                      <div className="space-y-1">
                        <Badge variant="secondary">{item.operation}</Badge>
                        <div className="text-xs text-muted-foreground">
                          {item.revision_reason ?? '自动记录'}
                        </div>
                      </div>
                    </TableCell>
                    <TableCell className="text-sm text-muted-foreground">
                      {item.actor_username ?? item.actor_email ?? 'system'}
                    </TableCell>
                    <TableCell className="text-muted-foreground">{item.created_at}</TableCell>
                    <TableCell className="text-right">
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={() => void openDetail(item.id)}
                        data-testid={`revision-open-${item.id}`}
                      >
                        <History className="h-4 w-4" />
                        查看 / 对比
                      </Button>
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle>当前选中版本</CardTitle>
            <CardDescription>支持查看快照、对比当前线上版本或另一历史版本，并按不同模式回滚。</CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            {selected ? (
              <>
                <div className="rounded-2xl border border-border/70 bg-background/70 p-4 text-sm">
                  <div className="flex flex-wrap items-center gap-2">
                    <Badge variant="secondary">{selected.item.operation}</Badge>
                    <Badge variant="outline">#{selected.item.id}</Badge>
                  </div>
                  <p className="mt-3 font-medium">{selected.item.post_title ?? selected.item.post_slug}</p>
                  <p className="mt-1 font-mono text-xs text-muted-foreground">
                    {selected.item.post_slug} · {selected.item.created_at}
                  </p>
                </div>

                <div className="space-y-2">
                  <LabelRow title="比较基线" />
                  <Select value={compareTarget} onChange={(event) => setCompareTarget(event.target.value)}>
                    <option value="current">当前线上版本</option>
                    {compareCandidates.map((item) => (
                      <option key={item.id} value={String(item.id)}>
                        #{item.id} · {item.created_at}
                      </option>
                    ))}
                  </Select>
                </div>

                <div className="grid gap-3 md:grid-cols-2">
                  <div className="rounded-2xl border border-border/70 bg-background/50 p-4 text-sm">
                    <div className="flex items-center gap-2 text-foreground">
                      <ArrowLeftRight className="h-4 w-4" />
                      <span>Diff 摘要</span>
                    </div>
                    <div className="mt-3 flex flex-wrap gap-2">
                      <Badge variant="success">+{diffStats.additions}</Badge>
                      <Badge variant="secondary">-{diffStats.deletions}</Badge>
                      <Badge variant="outline">metadata 变更 {metadataChanges.length}</Badge>
                    </div>
                    <div className="mt-3 text-xs leading-6 text-muted-foreground">
                      基线：{comparisonLabel}
                      {metadataChanges.length ? ` · 变化字段：${metadataChanges.join('、')}` : ' · Frontmatter 无变化'}
                    </div>
                  </div>
                  <div className="rounded-2xl border border-border/70 bg-background/50 p-4 text-sm">
                    <div className="font-medium text-foreground">恢复模式</div>
                    <div className="mt-3 flex flex-wrap gap-2">
                      {(['full', 'markdown', 'metadata'] as RestoreMode[]).map((mode) => (
                        <Button
                          key={mode}
                          size="sm"
                          disabled={restoring !== null || !selected.item.has_markdown}
                          data-testid={`revision-restore-${mode}`}
                          onClick={() => void runRestore(mode)}
                        >
                          <RotateCcw className="h-4 w-4" />
                          {restoring === `${selected.item.id}:${mode}` ? '恢复中...' : mode}
                        </Button>
                      ))}
                    </div>
                    <div className="mt-3 text-xs leading-6 text-muted-foreground">
                      full：整篇恢复；markdown：只恢复正文；metadata：只恢复 frontmatter / SEO / 生命周期等元信息。
                    </div>
                  </div>
                </div>

                <div className="grid gap-4 xl:grid-cols-2">
                  <div className="space-y-2">
                    <LabelRow title={comparisonLabel} />
                    <Textarea
                      value={comparisonMarkdown}
                      readOnly
                      className="min-h-[280px] font-mono text-xs leading-6"
                    />
                  </div>
                  <div className="space-y-2">
                    <LabelRow title={`版本 #${selected.item.id}`} />
                    <Textarea
                      value={selected.markdown ?? ''}
                      readOnly
                      className="min-h-[280px] font-mono text-xs leading-6"
                    />
                  </div>
                </div>
              </>
            ) : (
              <div className="rounded-2xl border border-dashed border-border/70 bg-background/50 px-4 py-10 text-center text-sm text-muted-foreground">
                先从左侧选择一个版本，右侧会显示对应快照内容与 Diff 摘要。
              </div>
            )}
          </CardContent>
        </Card>
      </div>
    </div>
  )
}

function LabelRow({ title }: { title: string }) {
  return <div className="text-sm font-medium text-foreground">{title}</div>
}
