'use client'

import Link from 'next/link'
import { useEffect, useMemo, useState } from 'react'
import { AlertTriangle, Check, Eye, EyeOff, RotateCcw, Save, Search, Upload, X } from 'lucide-react'
import { AdminShell } from '@/components/admin/AdminShell'
import { backend, type BackendRecommendationCandidate, type BackendRecommendationPlacement, type BackendRecommendationSlot, type BackendRecommendationSourceType } from '@/lib/backend'

type PlacementConfig = {
  key: BackendRecommendationPlacement
  label: string
  description: string
  sourceType: BackendRecommendationSourceType
}

const placements: PlacementConfig[] = [
  { key: 'home.news', label: '首页新闻', description: '首页动态模块：1 个主位 + 2 个副位', sourceType: 'news' },
  { key: 'home.courses', label: '首页课程', description: '首页近期课程固定 3 个位置', sourceType: 'course' },
  { key: 'home.events', label: '首页活动', description: '首页近期活动固定 4 个位置', sourceType: 'event' },
  { key: 'home.experts', label: '首页专家', description: '首页专家精选固定 4 个位置', sourceType: 'expert' },
  { key: 'news.carousel', label: '资讯轮播', description: '新闻资讯页顶部轮播固定 3 个位置', sourceType: 'news' },
  { key: 'courses.carousel', label: '课程轮播', description: '课程列表页顶部轮播固定 5 个位置', sourceType: 'course' },
  { key: 'events.carousel', label: '活动轮播', description: '活动列表页顶部轮播固定 5 个位置', sourceType: 'event' },
]

const sourceTypeLabels: Record<BackendRecommendationSourceType, string> = {
  news: '资讯',
  course: '课程',
  event: '活动',
  expert: '专家',
}

const slotLabels: Record<string, string> = {
  primary: '主推荐',
  secondary_1: '副推荐 1',
  secondary_2: '副推荐 2',
  slot_1: '位置 1',
  slot_2: '位置 2',
  slot_3: '位置 3',
  slot_4: '位置 4',
  slide_1: '轮播 1',
  slide_2: '轮播 2',
  slide_3: '轮播 3',
  slide_4: '轮播 4',
  slide_5: '轮播 5',
}

function groupSlots(items: BackendRecommendationSlot[]) {
  return Object.fromEntries(placements.map((placement) => [
    placement.key,
    items.filter((slot) => slot.placementKey === placement.key).sort((a, b) => a.sortOrder - b.sortOrder),
  ])) as Record<BackendRecommendationPlacement, BackendRecommendationSlot[]>
}

function sourceTitle(candidate?: BackendRecommendationCandidate) {
  if (!candidate) return '未选择内容'
  return candidate.title || candidate.id
}

function finalSlotHref(slot: BackendRecommendationSlot, candidate?: BackendRecommendationCandidate) {
  return slot.hrefOverride || candidate?.href || slot.href || ''
}

function finalSlotImage(slot: BackendRecommendationSlot, candidate?: BackendRecommendationCandidate) {
  return slot.imageUrlOverride || candidate?.imageUrl || slot.imageUrl || ''
}

export default function AdminSiteRecommendationsPage() {
  const [activePlacement, setActivePlacement] = useState<BackendRecommendationPlacement>('home.news')
  const [slots, setSlots] = useState<BackendRecommendationSlot[]>([])
  const [candidates, setCandidates] = useState<Record<BackendRecommendationSourceType, BackendRecommendationCandidate[]>>({
    news: [],
    course: [],
    event: [],
    expert: [],
  })
  const [keyword, setKeyword] = useState('')
  const [status, setStatus] = useState<'published' | 'all'>('published')
  const [loading, setLoading] = useState(true)
  const [saving, setSaving] = useState(false)
  const [uploadingSlot, setUploadingSlot] = useState('')
  const [error, setError] = useState('')
  const [savedAt, setSavedAt] = useState('')

  const activeConfig = placements.find((placement) => placement.key === activePlacement) || placements[0]
  const groupedSlots = useMemo(() => groupSlots(slots), [slots])
  const activeSlots = groupedSlots[activePlacement] || []
  const candidateItems = candidates[activeConfig.sourceType] || []
  const candidateById = new Map(candidateItems.map((item) => [item.id, item]))

  async function load(nextStatus = status, nextKeyword = keyword) {
    setLoading(true)
    setError('')
    try {
      const [slotResult, news, course, event, expert] = await Promise.all([
        backend.adminRecommendationSlots(),
        backend.adminRecommendationCandidates({ sourceType: 'news', status: nextStatus, keyword: nextKeyword }),
        backend.adminRecommendationCandidates({ sourceType: 'course', status: nextStatus, keyword: nextKeyword }),
        backend.adminRecommendationCandidates({ sourceType: 'event', status: nextStatus, keyword: nextKeyword }),
        backend.adminRecommendationCandidates({ sourceType: 'expert', status: nextStatus, keyword: nextKeyword }),
      ])
      setSlots(slotResult.items)
      setCandidates({ news: news.items, course: course.items, event: event.items, expert: expert.items })
    } catch (err) {
      setError(err instanceof Error ? err.message : '推荐位配置加载失败')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  function patchSlot(target: BackendRecommendationSlot, patch: Partial<BackendRecommendationSlot>) {
    setSlots((current) => current.map((slot) => (
      slot.placementKey === target.placementKey && slot.slotKey === target.slotKey
        ? { ...slot, ...patch }
        : slot
    )))
  }

  async function uploadSlotImage(slot: BackendRecommendationSlot, file: File | null | undefined) {
    if (!file) return
    const key = `${slot.placementKey}:${slot.slotKey}`
    setUploadingSlot(key)
    setError('')
    try {
      const uploaded = await backend.uploadAdminFile(file)
      patchSlot(slot, { imageUrlOverride: uploaded.url })
    } catch (err) {
      setError(err instanceof Error ? err.message : '覆盖图片上传失败')
    } finally {
      setUploadingSlot('')
    }
  }

  async function save() {
    setSaving(true)
    setError('')
    try {
      const payload = slots.map((slot) => ({
        ...slot,
        status: slot.sourceId ? slot.status : 'hidden',
      }))
      const saved = await backend.saveAdminRecommendationSlots(payload)
      setSlots(saved.items)
      setSavedAt(new Date().toLocaleString('zh-CN'))
    } catch (err) {
      setError(err instanceof Error ? err.message : '保存推荐位失败')
    } finally {
      setSaving(false)
    }
  }

  const visibleCount = activeSlots.filter((slot) => slot.status === 'active' && slot.sourceId).length
  const warningCount = slots.reduce((total, slot) => total + (slot.warnings?.length || 0), 0)

  return (
    <AdminShell title="推荐位配置" description="固定配置首页新闻、课程、活动、专家，以及资讯、课程、活动列表页轮播位。">
      <div className="grid min-h-[calc(100vh-104px)] gap-3 lg:grid-cols-[184px_1fr]">
        <aside className="overflow-hidden border border-line bg-white">
          <div className="border-b border-line px-3 py-2 text-xs font-extrabold text-soft">推荐位置</div>
          <div className="space-y-1 p-2">
            {placements.map((placement) => {
              const count = groupedSlots[placement.key]?.filter((slot) => slot.sourceId && slot.status === 'active').length || 0
              const active = placement.key === activePlacement
              return (
                <button
                  key={placement.key}
                  type="button"
                  onClick={() => setActivePlacement(placement.key)}
                  className={`w-full rounded-[4px] px-2 py-2 text-left transition ${active ? 'bg-brand text-white' : 'hover:bg-bg text-ink'}`}
                >
                  <div className="flex items-center justify-between gap-2 text-xs font-extrabold">
                    <span>{placement.label}</span>
                    <span className={active ? 'text-white/80' : 'text-soft'}>{count}</span>
                  </div>
                  <div className={`mt-1 line-clamp-2 text-[11px] leading-4 ${active ? 'text-white/75' : 'text-soft'}`}>{placement.description}</div>
                </button>
              )
            })}
          </div>
        </aside>

        <section className="min-w-0 overflow-hidden border border-line bg-white">
          <div className="flex flex-wrap items-center justify-between gap-3 border-b border-line px-3 py-2">
            <div>
              <div className="text-sm font-extrabold text-ink">{activeConfig.label}</div>
              <div className="mt-0.5 text-[11px] font-bold text-soft">{activeConfig.description} · 类型：{sourceTypeLabels[activeConfig.sourceType]} · 已显示 {visibleCount}/{activeSlots.length}</div>
            </div>
            <div className="flex flex-wrap items-center gap-2">
              {savedAt && <span className="text-[11px] font-bold text-soft">已保存 {savedAt}</span>}
              {warningCount > 0 && <span className="inline-flex h-7 items-center gap-1 rounded-[4px] bg-amber-50 px-2 text-[11px] font-extrabold text-amber-700"><AlertTriangle className="h-3.5 w-3.5" />{warningCount}</span>}
              <Link href="/admin/site/home" className="inline-flex h-8 items-center rounded-[4px] border border-line px-3 text-xs font-extrabold text-ink hover:border-brand hover:text-brand">
                首页配置
              </Link>
              <button type="button" onClick={save} disabled={saving || loading} className="inline-flex h-8 items-center gap-1.5 rounded-[4px] bg-brand px-3 text-xs font-extrabold text-white disabled:bg-line-dark">
                <Save className="h-3.5 w-3.5" />
                {saving ? '保存中' : '保存'}
              </button>
            </div>
          </div>

          <div className="flex flex-wrap items-center gap-2 border-b border-line bg-bg/50 px-3 py-2">
            <div className="relative min-w-[240px] flex-1">
              <Search className="pointer-events-none absolute left-2.5 top-2.5 h-3.5 w-3.5 text-soft" />
              <input
                value={keyword}
                onChange={(event) => setKeyword(event.target.value)}
                onKeyDown={(event) => {
                  if (event.key === 'Enter') void load(status, keyword)
                }}
                className="h-8 w-full rounded-[4px] border border-line bg-white pl-8 pr-3 text-xs"
                placeholder="搜索标题、摘要、讲师、地点或专家"
              />
            </div>
            <select
              value={status}
              onChange={(event) => {
                const next = event.target.value as 'published' | 'all'
                setStatus(next)
                void load(next, keyword)
              }}
              className="h-8 rounded-[4px] border border-line bg-white px-2 text-xs font-bold"
            >
              <option value="published">只看已发布</option>
              <option value="all">全部状态</option>
            </select>
            <button type="button" onClick={() => void load(status, keyword)} className="inline-flex h-8 items-center gap-1.5 rounded-[4px] border border-line bg-white px-3 text-xs font-extrabold text-ink hover:border-brand hover:text-brand">
              <RotateCcw className="h-3.5 w-3.5" />
              刷新
            </button>
          </div>

          {error && <div className="border-b border-red-100 bg-red-50 px-3 py-2 text-xs font-bold text-red-700">{error}</div>}

          <div className="max-h-[calc(100vh-230px)] overflow-y-auto">
            {loading ? (
              <div className="px-3 py-10 text-center text-xs font-bold text-soft">正在加载推荐位配置...</div>
            ) : (
              <div className="divide-y divide-line">
                {activeSlots.map((slot) => {
                  const selected = candidateById.get(slot.sourceId)
                  const warnings = slot.warnings || []
                  const imageUrl = finalSlotImage(slot, selected)
                  const href = finalSlotHref(slot, selected)
                  return (
                    <div key={`${slot.placementKey}-${slot.slotKey}`} className="px-3 py-3">
                      <div className="grid gap-2 lg:grid-cols-[96px_92px_minmax(220px,1fr)_88px_96px_auto] lg:items-center">
                        <div>
                          <div className="text-xs font-extrabold text-ink">{slotLabels[slot.slotKey] || slot.slotKey}</div>
                          <div className="mt-1 text-[11px] font-bold text-soft">{slot.slotKey}</div>
                        </div>
                        <div className="h-12 overflow-hidden rounded-[4px] border border-line bg-bg bg-cover bg-center" style={{ backgroundImage: imageUrl ? `url(${imageUrl})` : undefined }}>
                          {!imageUrl && <div className="grid h-full place-items-center text-[11px] font-bold text-soft">无图</div>}
                        </div>
                        <select
                          value={slot.sourceId || ''}
                          onChange={(event) => patchSlot(slot, { sourceId: event.target.value, status: event.target.value ? 'active' : 'hidden' })}
                          className="h-8 min-w-0 rounded-[4px] border border-line bg-white px-2 text-xs"
                        >
                          <option value="">不选择，隐藏此位置</option>
                          {slot.sourceId && !selected && (
                            <option value={slot.sourceId}>{slot.title || slot.sourceId}</option>
                          )}
                          {candidateItems.map((candidate) => (
                            <option key={candidate.id} value={candidate.id}>{sourceTitle(candidate)}</option>
                          ))}
                        </select>
                        <select
                          value={slot.status}
                          onChange={(event) => patchSlot(slot, { status: event.target.value as BackendRecommendationSlot['status'] })}
                          className="h-8 rounded-[4px] border border-line bg-white px-2 text-xs font-bold"
                        >
                          <option value="active">显示</option>
                          <option value="hidden">隐藏</option>
                        </select>
                        <button
                          type="button"
                          onClick={() => patchSlot(slot, { status: slot.status === 'active' ? 'hidden' : 'active' })}
                          className="inline-flex h-8 items-center justify-center gap-1.5 rounded-[4px] border border-line px-2 text-xs font-extrabold text-ink hover:border-brand hover:text-brand"
                        >
                          {slot.status === 'active' ? <Eye className="h-3.5 w-3.5" /> : <EyeOff className="h-3.5 w-3.5" />}
                          {slot.status === 'active' ? '显示' : '隐藏'}
                        </button>
                        <button
                          type="button"
                          onClick={() => patchSlot(slot, { sourceId: '', status: 'hidden', titleOverride: '', subtitleOverride: '', imageUrlOverride: '', ctaLabelOverride: '', hrefOverride: '' })}
                          className="inline-flex h-8 items-center justify-center rounded-[4px] border border-red-100 px-2 text-xs font-extrabold text-red-600 hover:bg-red-50"
                        >
                          <X className="h-3.5 w-3.5" />
                        </button>
                      </div>

                      <details className="mt-2 rounded-[4px] border border-line bg-bg/40">
                        <summary className="cursor-pointer px-3 py-2 text-[11px] font-extrabold text-soft">
                          覆盖文案 / 链接 / 图片
                        </summary>
                        <div className="grid gap-2 border-t border-line p-3 md:grid-cols-5">
                          <input value={slot.titleOverride || ''} onChange={(event) => patchSlot(slot, { titleOverride: event.target.value })} className="h-8 rounded-[4px] border border-line px-2 text-xs" placeholder="覆盖标题" />
                          <input value={slot.subtitleOverride || ''} onChange={(event) => patchSlot(slot, { subtitleOverride: event.target.value })} className="h-8 rounded-[4px] border border-line px-2 text-xs" placeholder="覆盖副标题" />
                          <div className="flex min-w-0 items-center gap-1">
                            <input value={slot.imageUrlOverride || ''} readOnly className="h-8 min-w-0 flex-1 rounded-[4px] border border-line bg-white px-2 text-xs text-muted" placeholder="上传覆盖图片" />
                            <label className="inline-flex h-8 shrink-0 cursor-pointer items-center gap-1 rounded-[4px] border border-line bg-white px-2 text-xs font-extrabold text-ink hover:border-brand hover:text-brand">
                              <Upload className="h-3.5 w-3.5" />
                              {uploadingSlot === `${slot.placementKey}:${slot.slotKey}` ? '上传中' : '上传'}
                              <input type="file" accept="image/*" className="sr-only" onChange={(event) => void uploadSlotImage(slot, event.target.files?.[0])} />
                            </label>
                          </div>
                          <input value={slot.ctaLabelOverride || ''} onChange={(event) => patchSlot(slot, { ctaLabelOverride: event.target.value })} className="h-8 rounded-[4px] border border-line px-2 text-xs" placeholder="覆盖 CTA" />
                          <input value={slot.hrefOverride || ''} onChange={(event) => patchSlot(slot, { hrefOverride: event.target.value })} className="h-8 rounded-[4px] border border-line px-2 text-xs" placeholder="覆盖跳转链接" />
                        </div>
                      </details>

                      <div className="mt-2 flex flex-wrap items-center gap-2 text-[11px] font-bold">
                        {selected && <span className="inline-flex items-center gap-1 rounded-[3px] bg-brand-light px-2 py-0.5 text-brand"><Check className="h-3 w-3" />{selected.status || 'published'} · {selected.badge || sourceTypeLabels[selected.sourceType]}</span>}
                        <span className={`inline-flex max-w-full items-center gap-1 rounded-[3px] px-2 py-0.5 ${href ? 'bg-bg text-muted' : 'bg-red-50 text-red-700'}`}>
                          跳转：<span className="truncate">{href || '未生成路径'}</span>
                        </span>
                        {warnings.map((warning) => (
                          <span key={warning} className="inline-flex items-center gap-1 rounded-[3px] bg-amber-50 px-2 py-0.5 text-amber-700"><AlertTriangle className="h-3 w-3" />{warning}</span>
                        ))}
                      </div>
                    </div>
                  )
                })}
              </div>
            )}
          </div>
        </section>
      </div>
    </AdminShell>
  )
}
