import { useEffect, useMemo, useRef, useState } from 'react'
import {
  Download,
  ExternalLink,
  File,
  FileSpreadsheet,
  FileText,
  Files,
  Presentation,
  Search,
  Trash2,
  Wand2
} from 'lucide-react'
import { useLocation } from 'react-router-dom'
import { toast } from 'sonner'

import { DashboardFooter } from '@renderer/components/dashboard/DashboardFooter'
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger
} from '@renderer/components/ui/alert-dialog'
import { Badge } from '@renderer/components/ui/badge'
import { Button } from '@renderer/components/ui/button'
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle
} from '@renderer/components/ui/card'
import {
  Drawer,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle
} from '@renderer/components/ui/drawer'
import { Input } from '@renderer/components/ui/input'
import { ScrollArea } from '@renderer/components/ui/scroll-area'
import { Select } from '@renderer/components/ui/select'
import type {
  ClassProfile,
  ChildProfile,
  ReportFormat,
  ReportGenerationProgress,
  ReportItem,
  TemplateItem
} from '@renderer/types/app'

const formatOptions: Array<{ value: ReportFormat | 'all'; label: string }> = [
  { value: 'all', label: '全部格式' },
  { value: 'word', label: 'Word' },
  { value: 'ppt', label: 'PPT' },
  { value: 'pdf', label: 'PDF' },
  { value: 'excel', label: 'Excel' }
]

function getReportFormatLabel(format: ReportFormat): string {
  const option = formatOptions.find((item) => item.value === format)

  return option?.label ?? '文件'
}

function getReportIcon(format: ReportFormat): typeof FileText {
  if (format === 'ppt') {
    return Presentation
  }

  if (format === 'excel') {
    return FileSpreadsheet
  }

  if (format === 'pdf') {
    return File
  }

  return FileText
}

function formatDateTime(value: string): string {
  const date = new Date(value)

  if (Number.isNaN(date.getTime())) {
    return value || '未生成'
  }

  return date.toLocaleString('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit'
  })
}

type ReportPageLocationState = {
  profileId?: string
  classId?: string
  mode?: 'view'
  autoGenerate?: boolean
}

export function ReportPage(): React.JSX.Element {
  const location = useLocation()
  const locationState = location.state as ReportPageLocationState | null
  const autoGenerateKeyRef = useRef('')
  const [classes, setClasses] = useState<ClassProfile[]>([])
  const [profiles, setProfiles] = useState<ChildProfile[]>([])
  const [templates, setTemplates] = useState<TemplateItem[]>([])
  const [reports, setReports] = useState<ReportItem[]>([])
  const [generationProgress, setGenerationProgress] = useState<ReportGenerationProgress | null>(
    null
  )
  const [query, setQuery] = useState('')
  const [selectedClassId, setSelectedClassId] = useState(locationState?.classId ?? 'all')
  const [generateDrawerOpen, setGenerateDrawerOpen] = useState(false)
  const [generateClassId, setGenerateClassId] = useState(locationState?.classId ?? '')
  const [selectedFormat, setSelectedFormat] = useState<ReportFormat | 'all'>('all')
  const [selectedTemplateId, setSelectedTemplateId] = useState('')
  const [generating, setGenerating] = useState(false)
  const [openingId, setOpeningId] = useState('')
  const [downloadingId, setDownloadingId] = useState('')
  const [deletingId, setDeletingId] = useState('')
  const [deletingAllReports, setDeletingAllReports] = useState(false)
  const [pendingStudentId, setPendingStudentId] = useState<string | null>(
    locationState?.profileId ?? null
  )

  useEffect(() => {
    async function loadPageData(): Promise<void> {
      const [studentResponse, templateResponse, reportResponse] = await Promise.all([
        window.api.loadStudentData({ includeImages: false }),
        window.api.loadTemplates(),
        window.api.loadReports()
      ])

      if (!studentResponse.ok) {
        toast.error('读取班级失败', { description: studentResponse.message })
      } else {
        setClasses(studentResponse.classes)
        setProfiles(studentResponse.profiles)
      }

      if (!templateResponse.ok) {
        toast.error('读取模板失败', { description: templateResponse.message })
      } else {
        setTemplates(templateResponse.templates)
        setSelectedTemplateId(
          templateResponse.templates.find((template) => template.fileExtension === '.pptx')?.id ??
            ''
        )
      }

      if (!reportResponse.ok) {
        toast.error('读取报告失败', { description: reportResponse.message })
      } else {
        setReports(reportResponse.reports)
      }
    }

    loadPageData()
  }, [])

  useEffect(() => {
    return window.api.onReportGenerationProgress((progress) => {
      setGenerationProgress(
        progress.status === 'finished' || progress.status === 'stopped' ? null : progress
      )

      if (progress.status === 'student-finished' && progress.report) {
        setReports((currentReports) => [progress.report!, ...currentReports])
      }
    })
  }, [])

  useEffect(() => {
    if (!pendingStudentId || profiles.length === 0) {
      return
    }

    const profile = profiles.find((item) => item.id === pendingStudentId)

    if (!profile) {
      return
    }

    queueMicrotask(() => {
      setSelectedClassId(profile.classId)
      setQuery(profile.name || profile.englishName)

      if (locationState?.mode === 'view') {
        setPendingStudentId(null)
        return
      }

      if (selectedTemplateId) {
        void handleGenerateReports({
          classId: profile.classId,
          studentIds: [profile.id]
        })
        setPendingStudentId(null)
      }
    })
  }, [locationState?.mode, pendingStudentId, profiles, selectedTemplateId])

  useEffect(() => {
    const autoGenerateKey = locationState?.classId
      ? `${locationState.classId}:${selectedTemplateId}`
      : ''

    if (
      !locationState?.autoGenerate ||
      !locationState.classId ||
      !selectedTemplateId ||
      selectedClassId !== locationState.classId ||
      generating ||
      autoGenerateKeyRef.current === autoGenerateKey
    ) {
      return
    }

    autoGenerateKeyRef.current = autoGenerateKey
    void handleGenerateReports({ classId: locationState.classId })
  }, [
    generating,
    locationState?.autoGenerate,
    locationState?.classId,
    selectedTemplateId,
    selectedClassId
  ])

  const pptxTemplates = templates.filter((template) => template.fileExtension === '.pptx')

  const filteredReports = useMemo(() => {
    const keyword = query.trim().toLowerCase()

    return reports.filter((report) => {
      const matchesKeyword =
        !keyword ||
        [
          report.title,
          report.className,
          report.studentName,
          report.originalFileName,
          getReportFormatLabel(report.format)
        ]
          .join(' ')
          .toLowerCase()
          .includes(keyword)
      const matchesClass = selectedClassId === 'all' || report.classId === selectedClassId
      const matchesFormat = selectedFormat === 'all' || report.format === selectedFormat

      return matchesKeyword && matchesClass && matchesFormat
    })
  }, [query, reports, selectedClassId, selectedFormat])

  async function handleGenerateReports(
    input: { classId?: string; studentIds?: string[] } = {}
  ): Promise<void> {
    const targetClassId = input.classId ?? selectedClassId

    if (!selectedTemplateId) {
      toast.error('请先选择 PPTX 报告模板')
      return
    }

    if (targetClassId === 'all') {
      toast.error('请选择要生成报告的班级')
      return
    }

    setGenerating(true)

    try {
      const response = await window.api.generateReports({
        templateId: selectedTemplateId,
        classId: targetClassId,
        studentIds: input.studentIds
      })

      if (!response.ok) {
        toast.error('生成报告失败', { description: response.message })
        return
      }

      setReports((currentReports) => {
        const existingIds = new Set(currentReports.map((report) => report.id))
        return [
          ...response.reports.filter((report) => !existingIds.has(report.id)),
          ...currentReports
        ]
      })
      toast.success(response.stopped ? '报告生成已停止' : '报告生成完成', {
        description:
          response.skipped.length > 0
            ? `成功 ${response.reports.length} 份，跳过 ${response.skipped.length} 份`
            : `成功 ${response.reports.length} 份`
      })
      setGenerateDrawerOpen(false)
    } finally {
      setGenerating(false)
    }
  }

  function openGenerateDrawer(): void {
    setGenerateClassId(selectedClassId === 'all' ? '' : selectedClassId)
    setGenerateDrawerOpen(true)
  }

  function handleConfirmGenerateClassReports(): void {
    if (!generateClassId) {
      toast.error('请选择要生成报告的班级')
      return
    }

    void handleGenerateReports({ classId: generateClassId })
  }

  async function handleDownloadReport(report: ReportItem): Promise<void> {
    setDownloadingId(report.id)

    try {
      const response = await window.api.downloadReport(report.id)

      if (!response.ok) {
        if (!response.canceled) {
          toast.error('下载报告失败', { description: response.message })
        }
        return
      }

      toast.success('报告已下载', { description: response.filePath })
    } finally {
      setDownloadingId('')
    }
  }

  async function handleOpenReport(report: ReportItem): Promise<void> {
    setOpeningId(report.id)

    try {
      const response = await window.api.openReport(report.filePath)

      if (!response.ok) {
        toast.error('打开报告失败', { description: response.message })
      }
    } finally {
      setOpeningId('')
    }
  }

  async function handleDeleteReport(report: ReportItem): Promise<void> {
    setDeletingId(report.id)

    try {
      const response = await window.api.deleteReport(report.id)

      if (!response.ok) {
        toast.error('删除报告失败', { description: response.message })
        return
      }

      setReports((currentReports) =>
        currentReports.filter((currentReport) => currentReport.id !== report.id)
      )
      toast.success(`已删除报告「${report.title}」`)
    } finally {
      setDeletingId('')
    }
  }

  async function handleDeleteAllReports(): Promise<void> {
    setDeletingAllReports(true)

    try {
      const response = await window.api.deleteAllReports()

      if (!response.ok) {
        toast.error('删除全部报告失败', { description: response.message })
        return
      }

      setReports([])

      if (response.deletedCount === 0) {
        toast.info('没有可删除的报告')
        return
      }

      toast.success('已删除全部报告', { description: `共删除 ${response.deletedCount} 份报告` })
    } finally {
      setDeletingAllReports(false)
    }
  }

  return (
    <>
      <section className="space-y-4 bg-white px-4 py-4">
        <div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
          <div>
            <CardTitle>
              <div className="flex items-center gap-2">
                <Files className="size-5 text-primary" />
                报告管理
              </div>
            </CardTitle>
            <CardDescription className="mt-1">
              管理已生成的成长报告，支持按班级、学生姓名和文件格式筛选。
            </CardDescription>
          </div>
          <Badge variant={filteredReports.length > 0 ? 'success' : 'secondary'}>
            {filteredReports.length} 份报告
          </Badge>
        </div>

        <div className="grid gap-3 rounded-md border border-dashed bg-muted/30 p-4">
          <div className="grid gap-3 xl:grid-cols-[minmax(0,1fr)_220px_180px]">
            <div className="relative min-w-0">
              <Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
              <Input
                className="pl-9"
                value={query}
                onChange={(event) => setQuery(event.target.value)}
                placeholder="搜索学生姓名、班级、报告名称或文件名"
              />
            </div>
            <Select
              value={selectedClassId}
              onChange={(event) => setSelectedClassId(event.target.value)}
            >
              <option value="all">全部班级</option>
              {classes.map((classItem) => (
                <option key={classItem.id} value={classItem.id}>
                  {classItem.name}
                </option>
              ))}
            </Select>
            <Select
              value={selectedFormat}
              onChange={(event) => setSelectedFormat(event.target.value as ReportFormat | 'all')}
            >
              {formatOptions.map((option) => (
                <option key={option.value} value={option.value}>
                  {option.label}
                </option>
              ))}
            </Select>
          </div>
          <div className="flex flex-col justify-end gap-2 sm:flex-row">
            <Button disabled={generating} onClick={openGenerateDrawer}>
              <Wand2 />
              {generating ? '生成中' : '生成班级报告'}
            </Button>
            <AlertDialog>
              <AlertDialogTrigger asChild>
                <Button
                  variant="destructive"
                  disabled={
                    deletingAllReports || reports.length === 0 || Boolean(generationProgress)
                  }
                >
                  <Trash2 />
                  {deletingAllReports ? '删除中' : '删除全部报告'}
                </Button>
              </AlertDialogTrigger>
              <AlertDialogContent>
                <AlertDialogHeader>
                  <AlertDialogTitle>删除全部报告？</AlertDialogTitle>
                  <AlertDialogDescription>
                    将删除当前数据库中的全部报告记录和对应文件，并把所有学生的报告状态重置为未生成。
                  </AlertDialogDescription>
                </AlertDialogHeader>
                <AlertDialogFooter>
                  <AlertDialogCancel>取消</AlertDialogCancel>
                  <AlertDialogAction onClick={handleDeleteAllReports}>
                    确认删除全部
                  </AlertDialogAction>
                </AlertDialogFooter>
              </AlertDialogContent>
            </AlertDialog>
          </div>
        </div>

        <ScrollArea className="h-140">
          <div className="grid gap-3 pr-3 md:grid-cols-2 xl:grid-cols-3">
            {filteredReports.map((report) => {
              const ReportIcon = getReportIcon(report.format)

              return (
                <Card key={report.id} className="shadow-none">
                  <CardHeader className="space-y-4">
                    <div className="flex items-start justify-between gap-3">
                      <div className="grid size-11 shrink-0 place-items-center rounded-md bg-muted text-primary">
                        <ReportIcon className="size-5" />
                      </div>
                      <Badge variant="secondary">{getReportFormatLabel(report.format)}</Badge>
                    </div>
                    <div className="min-w-0">
                      <CardTitle className="truncate text-base">{report.title}</CardTitle>
                      <CardDescription className="mt-2 truncate">
                        {report.originalFileName}
                      </CardDescription>
                    </div>
                  </CardHeader>
                  <CardContent className="space-y-4">
                    <div className="grid grid-cols-2 gap-3">
                      <div className="rounded-md bg-muted px-3 py-2">
                        <p className="text-xs text-muted-foreground">班级</p>
                        <p className="mt-1 truncate font-medium">{report.className}</p>
                      </div>
                      <div className="rounded-md bg-muted px-3 py-2">
                        <p className="text-xs text-muted-foreground">学生</p>
                        <p className="mt-1 truncate font-medium">{report.studentName}</p>
                      </div>
                      <div className="col-span-2 rounded-md bg-muted px-3 py-2">
                        <p className="text-xs text-muted-foreground">生成时间</p>
                        <p className="mt-1 truncate text-sm">{formatDateTime(report.createdAt)}</p>
                      </div>
                    </div>

                    <div className="flex justify-end gap-2">
                      <Button
                        size="sm"
                        variant="outline"
                        disabled={downloadingId === report.id}
                        onClick={() => handleDownloadReport(report)}
                      >
                        <Download />
                        {downloadingId === report.id ? '下载中' : '下载'}
                      </Button>
                      <Button
                        size="sm"
                        disabled={openingId === report.id}
                        onClick={() => handleOpenReport(report)}
                      >
                        <ExternalLink />
                        {openingId === report.id ? '打开中' : '打开报告'}
                      </Button>
                      <Button
                        size="sm"
                        variant="destructive"
                        disabled={deletingId === report.id}
                        onClick={() => handleDeleteReport(report)}
                      >
                        <Trash2 />
                        {deletingId === report.id ? '删除中' : '删除'}
                      </Button>
                    </div>
                  </CardContent>
                </Card>
              )
            })}

            {filteredReports.length === 0 && (
              <div className="col-span-full grid min-h-52 place-items-center rounded-md border bg-background p-6 text-center text-sm text-muted-foreground">
                <div className="space-y-3">
                  <div className="mx-auto grid size-12 place-items-center rounded-full bg-muted text-primary">
                    <Files className="size-5" />
                  </div>
                  <div>
                    <p className="font-medium text-foreground">暂无报告</p>
                    <p className="mt-1">选择班级和 PPTX 模板生成报告后，会以卡片形式显示在这里。</p>
                  </div>
                </div>
              </div>
            )}
          </div>
        </ScrollArea>
      </section>

      <Drawer direction="right" open={generateDrawerOpen} onOpenChange={setGenerateDrawerOpen}>
        <DrawerContent>
          <DrawerHeader>
            <DrawerTitle>生成班级报告</DrawerTitle>
            <DrawerDescription className="mt-1">
              选择一个班级和 PPTX 模板，系统会为该班级幼儿生成报告。
            </DrawerDescription>
          </DrawerHeader>
          <div className="space-y-5 p-6">
            <div className="grid gap-2">
              <label className="text-sm font-medium" htmlFor="generate-report-template">
                报告模板
              </label>
              <Select
                id="generate-report-template"
                value={selectedTemplateId}
                onChange={(event) => setSelectedTemplateId(event.target.value)}
              >
                <option value="">请选择 PPTX 报告模板</option>
                {pptxTemplates.map((template) => (
                  <option key={template.id} value={template.id}>
                    {template.name} - {template.originalFileName}
                  </option>
                ))}
              </Select>
            </div>
            <div className="grid gap-2">
              <label className="text-sm font-medium" htmlFor="generate-report-class">
                生成班级
              </label>
              <Select
                id="generate-report-class"
                value={generateClassId}
                onChange={(event) => setGenerateClassId(event.target.value)}
              >
                <option value="">请选择班级</option>
                {classes.map((classItem) => (
                  <option key={classItem.id} value={classItem.id}>
                    {classItem.name}
                  </option>
                ))}
              </Select>
            </div>
          </div>
          <DrawerFooter>
            <Button
              disabled={generating || !generateClassId || !selectedTemplateId}
              onClick={handleConfirmGenerateClassReports}
            >
              <Wand2 />
              {generating ? '生成中' : '确认生成'}
            </Button>
            <Button
              variant="outline"
              disabled={generating}
              onClick={() => setGenerateDrawerOpen(false)}
            >
              取消
            </Button>
          </DrawerFooter>
        </DrawerContent>
      </Drawer>

      <DashboardFooter />
    </>
  )
}
