import { useEffect, useMemo, useRef, useState } from 'react'
import { toast } from 'sonner'
import {
  Camera,
  Construction,
  FolderPlus,
  MoreHorizontal,
  Pencil,
  Plus,
  Search,
  Trash2,
  Upload,
  X
} from 'lucide-react'

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,
  DrawerHeader,
  DrawerTitle
} from '@renderer/components/ui/drawer'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger
} from '@renderer/components/ui/dropdown-menu'
import { Input } from '@renderer/components/ui/input'
import { ScrollArea } from '@renderer/components/ui/scroll-area'
import { Select } from '@renderer/components/ui/select'
import {
  classTypeOptions,
  createUuid,
  getClassTypeLabel
} from '@renderer/student/classes'
import {
  readChildProfilesFromSpreadsheet,
  replaceProfilesForClass
} from '@renderer/student/children'
import type { ChildProfile, ClassProfile, ClassType } from '@renderer/types/app'

type EditingClass = {
  id: string
  name: string
  type: ClassType
  familyPhoto?: string
}

export function ClassPage(): React.JSX.Element {
  const fileInputRef = useRef<HTMLInputElement>(null)
  const classPhotoInputRef = useRef<HTMLInputElement>(null)
  const editPhotoInputRef = useRef<HTMLInputElement>(null)
  const [classes, setClasses] = useState<ClassProfile[]>([])
  const [profiles, setProfiles] = useState<ChildProfile[]>([])
  const [className, setClassName] = useState('')
  const [classType, setClassType] = useState<ClassType>('cheap')
  const [classFamilyPhoto, setClassFamilyPhoto] = useState('')
  const [query, setQuery] = useState('')
  const [createDrawerOpen, setCreateDrawerOpen] = useState(false)
  const [exportingId, setExportingId] = useState('')
  const [editingClass, setEditingClass] = useState<EditingClass | null>(null)
  const [uploadingClass, setUploadingClass] = useState<ClassProfile | null>(null)
  const [selectedFile, setSelectedFile] = useState<File | null>(null)
  const [isDragActive, setIsDragActive] = useState(false)

  useEffect(() => {
    async function loadStudentData(): Promise<void> {
      const response = await window.api.loadStudentData()

      if (!response.ok) {
        showError('读取数据库失败', response.message)
        return
      }

      setClasses(response.classes)
      setProfiles(response.profiles)
    }

    loadStudentData()
  }, [])

  const profileCountByClass = useMemo(() => {
    const countMap = new Map<string, number>()

    for (const profile of profiles) {
      countMap.set(profile.classId, (countMap.get(profile.classId) ?? 0) + 1)
    }

    return countMap
  }, [profiles])

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

    if (!keyword) {
      return classes
    }

    return classes.filter((classItem) =>
      [classItem.name, classItem.id, getClassTypeLabel(classItem.type)]
        .join(' ')
        .toLowerCase()
        .includes(keyword)
    )
  }, [classes, query])

  function getProfilesByClass(classId: string): ChildProfile[] {
    return profiles.filter((profile) => profile.classId === classId)
  }

  function showSuccess(message: string, description?: string): void {
    toast.success(message, description ? { description } : undefined)
  }

  function showError(message: string, description?: string): void {
    toast.error(message, description ? { description } : undefined)
  }

  function readImageFile(file: File, onLoad: (dataUrl: string) => void): void {
    if (!file.type.startsWith('image/')) {
      showError('请选择图片文件')
      return
    }

    const reader = new FileReader()
    reader.addEventListener('load', () => {
      if (typeof reader.result === 'string') {
        onLoad(reader.result)
      }
    })
    reader.readAsDataURL(file)
  }

  function handleCreatePhotoChange(event: React.ChangeEvent<HTMLInputElement>): void {
    const file = event.target.files?.[0]

    if (!file) {
      return
    }

    readImageFile(file, setClassFamilyPhoto)
  }

  function handleEditPhotoChange(event: React.ChangeEvent<HTMLInputElement>): void {
    const file = event.target.files?.[0]

    if (!file || !editingClass) {
      return
    }

    readImageFile(file, (dataUrl) =>
      setEditingClass({
        ...editingClass,
        familyPhoto: dataUrl
      })
    )
  }

  async function handleCreateClass(): Promise<void> {
    const nextName = className.trim()

    if (!nextName) {
      showError('请输入班级名称')
      return
    }

    const existingClass = classes.find((classItem) => classItem.name === nextName)

    if (existingClass) {
      showError('班级已存在', '可以编辑类型或直接上传幼儿信息')
      return
    }

    const nextClasses = [
      ...classes,
      {
        id: createUuid(),
        name: nextName,
        type: classType,
        familyPhoto: classFamilyPhoto || undefined
      }
    ]
    const response = await window.api.saveClasses(nextClasses)

    if (!response.ok) {
      showError('新建班级失败', response.message)
      return
    }

    setClasses(nextClasses)
    setClassName('')
    setClassType('cheap')
    setClassFamilyPhoto('')
    if (classPhotoInputRef.current) {
      classPhotoInputRef.current.value = ''
    }
    setCreateDrawerOpen(false)
    showSuccess('班级已新建')
  }

  function handleOpenEdit(classItem: ClassProfile): void {
    setEditingClass({
      id: classItem.id,
      name: classItem.name,
      type: classItem.type,
      familyPhoto: classItem.familyPhoto
    })
  }

  async function handleSaveEdit(): Promise<void> {
    if (!editingClass) {
      return
    }

    const nextName = editingClass.name.trim()

    if (!nextName) {
      showError('班级名称不能为空')
      return
    }

    const duplicateClass = classes.find(
      (classItem) => classItem.id !== editingClass.id && classItem.name === nextName
    )

    if (duplicateClass) {
      showError('班级名称已存在')
      return
    }

    const nextClasses = classes.map((classItem) =>
      classItem.id === editingClass.id
        ? {
            ...classItem,
            name: nextName,
            type: editingClass.type,
            familyPhoto: editingClass.familyPhoto
          }
        : classItem
    )
    const nextProfiles = profiles.map((profile) =>
      profile.classId === editingClass.id
        ? {
            ...profile,
            className: nextName
          }
        : profile
    )

    const saveClassesResponse = await window.api.saveClasses(nextClasses)

    if (!saveClassesResponse.ok) {
      showError('保存班级失败', saveClassesResponse.message)
      return
    }

    setClasses(nextClasses)
    setProfiles(nextProfiles)
    setEditingClass(null)
    showSuccess('班级已更新')
  }

  async function handleDeleteClass(classItem: ClassProfile): Promise<void> {
    const response = await window.api.deleteClass(classItem.id)

    if (!response.ok) {
      showError('删除班级失败', response.message)
      return
    }

    setClasses(classes.filter((item) => item.id !== classItem.id))
    setProfiles(profiles.filter((profile) => profile.classId !== classItem.id))
    showSuccess(`已删除班级「${classItem.name}」及其幼儿数据`)
  }

  function selectImportFile(file?: File): void {
    if (!file) {
      return
    }

    if (!/\.(xlsx|xls)$/i.test(file.name)) {
      showError('请选择 .xlsx 或 .xls 文件')
      return
    }

    setSelectedFile(file)
  }

  function handleFileChange(event: React.ChangeEvent<HTMLInputElement>): void {
    selectImportFile(event.target.files?.[0])
  }

  function handleDrop(event: React.DragEvent<HTMLButtonElement>): void {
    event.preventDefault()
    setIsDragActive(false)
    selectImportFile(event.dataTransfer.files[0])
  }

  function openUploadDrawer(classItem: ClassProfile): void {
    setUploadingClass(classItem)
    setSelectedFile(null)
    setIsDragActive(false)

    if (fileInputRef.current) {
      fileInputRef.current.value = ''
    }
  }

  async function handleUploadSubmit(): Promise<void> {
    if (!uploadingClass) {
      return
    }

    if (!selectedFile) {
      showError('请选择要上传的 xlsx 文件')
      return
    }

    try {
      const nextProfiles = await readChildProfilesFromSpreadsheet(selectedFile, uploadingClass)
      const response = await window.api.replaceClassProfiles({
        classItem: uploadingClass,
        profiles: nextProfiles
      })

      if (!response.ok) {
        showError('保存幼儿信息失败', response.message)
        return
      }

      setProfiles(replaceProfilesForClass(profiles, uploadingClass, nextProfiles))
      setUploadingClass(null)
      setSelectedFile(null)
      setIsDragActive(false)
      showSuccess(`已上传「${uploadingClass.name}」幼儿信息`, `共 ${nextProfiles.length} 条`)
    } catch (error) {
      console.error(error)
      showError('上传失败', '请确认表头和示例一致，并使用 .xlsx 文件')
    } finally {
      if (fileInputRef.current) {
        fileInputRef.current.value = ''
      }
    }
  }

  async function handleExportClass(classItem: ClassProfile): Promise<void> {
    setExportingId(classItem.id)

    try {
      const result = await window.api.exportEmptyClassFolder({
        classId: classItem.id,
        className: classItem.name,
        childNames: getProfilesByClass(classItem.id).map(
          (profile) => profile.name || profile.englishName
        )
      })

      if (result.ok) {
        showSuccess(
          '已导出压缩包',
          `${result.zipPath}，包含 ${result.childFolderCount} 个幼儿文件夹`
        )
        return
      }

      if (!result.canceled) {
        showError(result.message)
      }
    } finally {
      setExportingId('')
    }
  }

  return (
    <>
      <section className="space-y-4 bg-white px-4 py-4 ">
        <div className="fle flex-col gap-3">
          <CardTitle>
            <div className="flex items-center gap-2">
              <Construction className="size-5 text-primary" />
              班级管理
            </div>
          </CardTitle>
          <CardDescription>管理班级信息</CardDescription>
        </div>
        <div className="grid gap-3 rounded-md border border-dashed bg-muted/30 p-4">
          <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="搜索班级名称、类型或 UUID"
            />
          </div>
          <div className="flex justify-end">
            <Button onClick={() => setCreateDrawerOpen(true)}>
              <Plus />
              新建班级
            </Button>
          </div>
        </div>

        <ScrollArea className="h-140">
          <div className="grid gap-3 pr-3 md:grid-cols-2 xl:grid-cols-3">
            {filteredClasses.map((classItem) => {
              const childCount = profileCountByClass.get(classItem.id) ?? 0

              return (
                <Card key={classItem.id} className="shadow-none">
                  <div className="aspect-video overflow-hidden rounded-t-lg bg-muted">
                    {classItem.familyPhoto ? (
                      <img
                        className="h-full w-full object-cover"
                        src={classItem.familyPhoto}
                        alt={classItem.name}
                      />
                    ) : (
                      <div className="grid h-full place-items-center text-sm text-muted-foreground">
                        <Camera className="mb-2 size-6" />
                        暂无班级全家福
                      </div>
                    )}
                  </div>
                  <CardHeader className="space-y-3 pb-3">
                    <div className="flex items-start justify-between gap-3">
                      <div className="min-w-0">
                        <CardTitle className="truncate text-base">{classItem.name}</CardTitle>
                        <CardDescription className="mt-1 break-all font-mono text-xs">
                          {classItem.id}
                        </CardDescription>
                      </div>
                      <Badge variant={classItem.type === 'noble' ? 'warning' : 'secondary'}>
                        {getClassTypeLabel(classItem.type)}
                      </Badge>
                    </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 text-xl font-semibold">{childCount} 条</p>
                      </div>
                      <div className="rounded-md bg-muted px-3 py-2">
                        <p className="text-xs text-muted-foreground">班级类型</p>
                        <p className="mt-1 font-medium">{getClassTypeLabel(classItem.type)}</p>
                      </div>
                    </div>

                    <div className="flex items-center justify-end gap-2">
                      <DropdownMenu>
                        <DropdownMenuTrigger asChild>
                          <Button size="sm" variant="outline">
                            <MoreHorizontal />
                            操作
                          </Button>
                        </DropdownMenuTrigger>
                        <DropdownMenuContent>
                          <DropdownMenuLabel>班级操作</DropdownMenuLabel>
                          <DropdownMenuSeparator />
                          <DropdownMenuItem onSelect={() => openUploadDrawer(classItem)}>
                            <Upload />
                            上传幼儿信息
                          </DropdownMenuItem>
                          <DropdownMenuItem
                            disabled={exportingId === classItem.id}
                            onSelect={() => handleExportClass(classItem)}
                          >
                            <FolderPlus />
                            {exportingId === classItem.id ? '导出中' : '导出 ZIP'}
                          </DropdownMenuItem>
                          <DropdownMenuItem onSelect={() => handleOpenEdit(classItem)}>
                            <Pencil />
                            编辑班级
                          </DropdownMenuItem>
                        </DropdownMenuContent>
                      </DropdownMenu>

                      <AlertDialog>
                        <AlertDialogTrigger asChild>
                          <Button size="sm" variant="destructive">
                            <Trash2 />
                            删除
                          </Button>
                        </AlertDialogTrigger>
                        <AlertDialogContent>
                          <AlertDialogHeader>
                            <AlertDialogTitle>删除「{classItem.name}」？</AlertDialogTitle>
                            <AlertDialogDescription>
                              当前班级是{getClassTypeLabel(classItem.type)}，共有 {childCount}{' '}
                              条幼儿数据。确认删除后，这个班级和班级里的幼儿数据都会被删除。
                            </AlertDialogDescription>
                          </AlertDialogHeader>
                          <AlertDialogFooter>
                            <AlertDialogCancel>取消</AlertDialogCancel>
                            <AlertDialogAction onClick={() => handleDeleteClass(classItem)}>
                              确认删除
                            </AlertDialogAction>
                          </AlertDialogFooter>
                        </AlertDialogContent>
                      </AlertDialog>
                    </div>
                  </CardContent>
                </Card>
              )
            })}

            {filteredClasses.length === 0 && (
              <div className="col-span-full grid h-28 place-items-center rounded-md border text-sm text-muted-foreground">
                暂无匹配班级，请先新建班级
              </div>
            )}
          </div>
        </ScrollArea>
      </section>

      <Drawer direction="right" open={createDrawerOpen} onOpenChange={setCreateDrawerOpen}>
        <DrawerContent>
          <DrawerHeader>
            <div className="flex items-start justify-between gap-3">
              <div>
                <DrawerTitle>新建班级</DrawerTitle>
                <DrawerDescription className="mt-1">
                  填写班级名称、类型，并上传班级全家福。
                </DrawerDescription>
              </div>
              <Button
                size="icon"
                variant="ghost"
                aria-label="关闭新建班级"
                onClick={() => setCreateDrawerOpen(false)}
              >
                <X />
              </Button>
            </div>
          </DrawerHeader>
          <div className="space-y-5 p-6">
            <div className="grid gap-2">
              <label className="text-sm font-medium" htmlFor="new-class-name">
                班级名称
              </label>
              <Input
                id="new-class-name"
                value={className}
                onChange={(event) => setClassName(event.target.value)}
                onKeyDown={(event) => {
                  if (event.key === 'Enter') {
                    handleCreateClass()
                  }
                }}
                placeholder="输入班级名称，例如：星星二班"
              />
            </div>

            <div className="grid gap-2">
              <label className="text-sm font-medium" htmlFor="new-class-type">
                班级类型
              </label>
              <Select
                id="new-class-type"
                value={classType}
                onChange={(event) => setClassType(event.target.value as ClassType)}
              >
                {classTypeOptions.map((option) => (
                  <option key={option.value} value={option.value}>
                    {option.label}
                  </option>
                ))}
              </Select>
            </div>

            <div className="grid gap-2">
              <p className="text-sm font-medium">班级全家福</p>
              <button
                type="button"
                className="relative grid aspect-video overflow-hidden rounded-md border border-dashed bg-muted transition-colors hover:border-primary"
                onClick={() => classPhotoInputRef.current?.click()}
              >
                {classFamilyPhoto ? (
                  <img
                    className="h-full w-full object-cover"
                    src={classFamilyPhoto}
                    alt="班级全家福预览"
                  />
                ) : (
                  <span className="grid place-items-center gap-2 p-4 text-center text-sm text-muted-foreground">
                    <Camera className="mx-auto size-5" />
                    上传班级全家福
                  </span>
                )}
              </button>
              <input
                ref={classPhotoInputRef}
                className="hidden"
                type="file"
                accept="image/*"
                onChange={handleCreatePhotoChange}
              />
              {classFamilyPhoto && (
                <div className="flex justify-end">
                  <Button size="sm" variant="outline" onClick={() => setClassFamilyPhoto('')}>
                    移除全家福
                  </Button>
                </div>
              )}
            </div>

            <div className="flex justify-end gap-2">
              <Button variant="outline" onClick={() => setCreateDrawerOpen(false)}>
                取消
              </Button>
              <Button onClick={handleCreateClass}>
                <Plus />
                确认新建
              </Button>
            </div>
          </div>
        </DrawerContent>
      </Drawer>

      <Drawer
        direction="right"
        open={Boolean(editingClass)}
        onOpenChange={() => setEditingClass(null)}
      >
        <DrawerContent>
          {editingClass && (
            <>
              <DrawerHeader>
                <div className="flex items-start justify-between gap-3">
                  <div>
                    <DrawerTitle>编辑班级</DrawerTitle>
                    <DrawerDescription className="mt-1">
                      修改班级名称或类型，班级下已有幼儿数据会同步班级名称。
                    </DrawerDescription>
                  </div>
                  <Button
                    size="icon"
                    variant="ghost"
                    aria-label="关闭编辑班级"
                    onClick={() => setEditingClass(null)}
                  >
                    <X />
                  </Button>
                </div>
              </DrawerHeader>
              <div className="space-y-5 p-6">
                <div className="grid gap-2">
                  <label className="text-sm font-medium" htmlFor="edit-class-name">
                    班级名称
                  </label>
                  <Input
                    id="edit-class-name"
                    value={editingClass.name}
                    onChange={(event) =>
                      setEditingClass({
                        ...editingClass,
                        name: event.target.value
                      })
                    }
                  />
                </div>
                <div className="grid gap-2">
                  <label className="text-sm font-medium" htmlFor="edit-class-type">
                    班级类型
                  </label>
                  <Select
                    id="edit-class-type"
                    value={editingClass.type}
                    onChange={(event) =>
                      setEditingClass({
                        ...editingClass,
                        type: event.target.value as ClassType
                      })
                    }
                  >
                    {classTypeOptions.map((option) => (
                      <option key={option.value} value={option.value}>
                        {option.label}
                      </option>
                    ))}
                  </Select>
                </div>
                <div className="grid gap-2">
                  <p className="text-sm font-medium">班级全家福</p>
                  <button
                    type="button"
                    className="relative grid aspect-[16/9] overflow-hidden rounded-md border border-dashed bg-muted transition-colors hover:border-primary"
                    onClick={() => editPhotoInputRef.current?.click()}
                  >
                    {editingClass.familyPhoto ? (
                      <img
                        className="h-full w-full object-cover"
                        src={editingClass.familyPhoto}
                        alt="班级全家福预览"
                      />
                    ) : (
                      <span className="grid place-items-center gap-2 p-4 text-center text-sm text-muted-foreground">
                        <Camera className="mx-auto size-5" />
                        上传班级全家福
                      </span>
                    )}
                  </button>
                  <input
                    ref={editPhotoInputRef}
                    className="hidden"
                    type="file"
                    accept="image/*"
                    onChange={handleEditPhotoChange}
                  />
                  {editingClass.familyPhoto && (
                    <div className="flex justify-end">
                      <Button
                        size="sm"
                        variant="outline"
                        onClick={() =>
                          setEditingClass({
                            ...editingClass,
                            familyPhoto: undefined
                          })
                        }
                      >
                        移除全家福
                      </Button>
                    </div>
                  )}
                </div>
                <div className="flex justify-end gap-2">
                  <Button variant="outline" onClick={() => setEditingClass(null)}>
                    取消
                  </Button>
                  <Button onClick={handleSaveEdit}>保存</Button>
                </div>
              </div>
            </>
          )}
        </DrawerContent>
      </Drawer>

      <Drawer
        direction="right"
        open={Boolean(uploadingClass)}
        onOpenChange={() => setUploadingClass(null)}
      >
        <DrawerContent>
          {uploadingClass && (
            <>
              <DrawerHeader>
                <div className="flex items-start justify-between gap-3">
                  <div>
                    <DrawerTitle>上传幼儿信息</DrawerTitle>
                    <DrawerDescription className="mt-1">
                      当前班级：{uploadingClass.name}，上传后会替换该班级已有幼儿数据。
                    </DrawerDescription>
                  </div>
                  <Button
                    size="icon"
                    variant="ghost"
                    aria-label="关闭上传幼儿信息"
                    onClick={() => setUploadingClass(null)}
                  >
                    <X />
                  </Button>
                </div>
              </DrawerHeader>
              <div className="space-y-5 p-6">
                <button
                  type="button"
                  className={[
                    'grid min-h-[180px] place-items-center rounded-md border border-dashed bg-muted/30 p-6 text-center transition-colors',
                    isDragActive
                      ? 'border-primary bg-accent'
                      : 'hover:border-primary hover:bg-muted/50'
                  ].join(' ')}
                  onClick={() => fileInputRef.current?.click()}
                  onDragEnter={(event) => {
                    event.preventDefault()
                    setIsDragActive(true)
                  }}
                  onDragOver={(event) => event.preventDefault()}
                  onDragLeave={() => setIsDragActive(false)}
                  onDrop={handleDrop}
                >
                  <div className="space-y-3">
                    <div className="mx-auto grid size-12 place-items-center rounded-full bg-primary text-primary-foreground">
                      <Upload className="size-5" />
                    </div>
                    <div>
                      <p className="font-medium">
                        {selectedFile ? selectedFile.name : '点击或拖拽 XLSX 文件到这里'}
                      </p>
                      <p className="mt-1 text-sm text-muted-foreground">支持 .xlsx 和 .xls 文件</p>
                    </div>
                  </div>
                </button>
                <input
                  ref={fileInputRef}
                  className="hidden"
                  type="file"
                  accept=".xlsx,.xls"
                  onChange={handleFileChange}
                />
                <div className="flex justify-end gap-2">
                  <Button variant="outline" onClick={() => setUploadingClass(null)}>
                    取消
                  </Button>
                  <Button onClick={handleUploadSubmit}>
                    <Upload />
                    确认上传
                  </Button>
                </div>
              </div>
            </>
          )}
        </DrawerContent>
      </Drawer>

      <DashboardFooter />
    </>
  )
}
