'use client'

import { PointerEvent, useEffect, useMemo, useRef, useState } from 'react'
import { FileJson, ImagePlus, MousePointer2, Upload } from 'lucide-react'

import { Button } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import {
  DEFAULT_TEMPLATE_CONFIG,
  type CertificateTemplateConfig,
  type Rect,
  denormalizeRect,
  normalizeRect
} from '@/lib/certificate-types'
import {
  type ActiveTool,
  type TemplateItem,
  createId,
  downloadText,
  hydrateTemplate,
  loadAppState,
  loadDefaultTemplateImage,
  persistImageSource,
  saveAppState
} from '@/lib/certificate-page-utils'
import { loadImageSource, type ImageSource } from '@/lib/certificate-browser'
import { cn } from '@/lib/utils'

function clamp(value: number, min: number, max: number) {
  return Math.min(Math.max(value, min), max)
}

export default function TemplatesPage() {
  const canvasRef = useRef<HTMLCanvasElement | null>(null)
  const [storedState, setStoredState] = useState<Awaited<ReturnType<typeof loadAppState>> | null>(null)
  const [templates, setTemplates] = useState<TemplateItem[]>([])
  const [activeTemplateId, setActiveTemplateId] = useState('')
  const [templateDraftName, setTemplateDraftName] = useState('亲爱版毕业证书')
  const [templateDraftImage, setTemplateDraftImage] = useState<ImageSource | null>(null)
  const [templateDraftConfig, setTemplateDraftConfig] =
    useState<CertificateTemplateConfig>(DEFAULT_TEMPLATE_CONFIG)
  const [activeTool, setActiveTool] = useState<ActiveTool>('image')
  const [dragStart, setDragStart] = useState<{ x: number; y: number } | null>(null)

  const activeTemplate = templates.find((template) => template.id === activeTemplateId) ?? templates[0]
  const renderedRects = useMemo(() => {
    if (!templateDraftImage) {
      return null
    }

    return {
      image: denormalizeRect(
        templateDraftConfig.imageRect,
        templateDraftImage.width,
        templateDraftImage.height
      ),
      name: denormalizeRect(
        templateDraftConfig.nameRect,
        templateDraftImage.width,
        templateDraftImage.height
      )
    }
  }, [templateDraftConfig.imageRect, templateDraftConfig.nameRect, templateDraftImage])

  useEffect(() => {
    async function loadTemplates() {
      const state = await loadAppState()
      const restoredTemplates = await Promise.all((state.templates ?? []).map(hydrateTemplate))
      const restoredActiveTemplate =
        restoredTemplates.find((template) => template.id === state.activeTemplateId) ??
        restoredTemplates[0]

      setStoredState(state)

      if (restoredActiveTemplate) {
        setTemplates(restoredTemplates)
        setActiveTemplateId(restoredActiveTemplate.id)
        setTemplateDraftName(restoredActiveTemplate.name)
        setTemplateDraftImage(restoredActiveTemplate.image)
        setTemplateDraftConfig(restoredActiveTemplate.config)
        return
      }

      const image = await loadDefaultTemplateImage()
      const template: TemplateItem = {
        id: createId('template'),
        name: '亲爱版毕业证书',
        image,
        config: {
          ...DEFAULT_TEMPLATE_CONFIG,
          templateWidth: image.width,
          templateHeight: image.height
        },
        updatedAt: new Date().toISOString()
      }

      setTemplates([template])
      setActiveTemplateId(template.id)
      setTemplateDraftName(template.name)
      setTemplateDraftImage(image)
      setTemplateDraftConfig(template.config)
    }

    loadTemplates()
  }, [])

  useEffect(() => {
    const canvas = canvasRef.current

    if (!canvas || !templateDraftImage || !renderedRects) {
      return
    }

    canvas.width = templateDraftImage.width
    canvas.height = templateDraftImage.height
    const context = canvas.getContext('2d')

    if (!context) {
      return
    }

    const image = new Image()
    image.onload = () => {
      context.clearRect(0, 0, canvas.width, canvas.height)
      context.drawImage(image, 0, 0, canvas.width, canvas.height)
      context.strokeStyle = activeTool === 'image' ? '#2563eb' : '#16a34a'
      context.lineWidth = 4
      context.setLineDash([14, 10])
      const rect = activeTool === 'image' ? renderedRects.image : renderedRects.name
      context.strokeRect(rect.x, rect.y, rect.width, rect.height)
      context.setLineDash([])
    }
    image.src = templateDraftImage.dataUrl
  }, [activeTool, renderedRects, templateDraftImage])

  function canvasPoint(event: PointerEvent<HTMLCanvasElement>) {
    const canvas = canvasRef.current

    if (!canvas || !templateDraftImage) {
      return null
    }

    const bounds = canvas.getBoundingClientRect()

    return {
      x: ((event.clientX - bounds.left) / bounds.width) * templateDraftImage.width,
      y: ((event.clientY - bounds.top) / bounds.height) * templateDraftImage.height
    }
  }

  function updateActiveRect(rect: Rect) {
    if (!templateDraftImage) {
      return
    }

    const normalized = normalizeRect(rect, templateDraftImage.width, templateDraftImage.height)
    setTemplateDraftConfig((current) => ({
      ...current,
      [activeTool === 'image' ? 'imageRect' : 'nameRect']: normalized
    }))
  }

  function handlePointerDown(event: PointerEvent<HTMLCanvasElement>) {
    const point = canvasPoint(event)

    if (point) {
      setDragStart(point)
    }
  }

  function handlePointerUp(event: PointerEvent<HTMLCanvasElement>) {
    if (!templateDraftImage || !dragStart) {
      return
    }

    const end = canvasPoint(event)
    setDragStart(null)

    if (!end) {
      return
    }

    const x = clamp(Math.min(dragStart.x, end.x), 0, templateDraftImage.width)
    const y = clamp(Math.min(dragStart.y, end.y), 0, templateDraftImage.height)
    const width = clamp(Math.abs(end.x - dragStart.x), 1, templateDraftImage.width - x)
    const height = clamp(Math.abs(end.y - dragStart.y), 1, templateDraftImage.height - y)

    if (width >= 12 && height >= 12) {
      updateActiveRect({ x, y, width, height })
    }
  }

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

    if (!file) {
      return
    }

    const image = await loadImageSource(file, file.name)
    setTemplateDraftImage(image)
    setTemplateDraftConfig((current) => ({
      ...current,
      templateWidth: image.width,
      templateHeight: image.height
    }))
  }

  async function saveTemplate() {
    if (!templateDraftImage || !templateDraftName.trim()) {
      return
    }

    const nextTemplate: TemplateItem = {
      id: activeTemplateId || createId('template'),
      name: templateDraftName.trim(),
      image: templateDraftImage,
      config: templateDraftConfig,
      updatedAt: new Date().toISOString()
    }
    const nextTemplates = templates.some((template) => template.id === nextTemplate.id)
      ? templates.map((template) => (template.id === nextTemplate.id ? nextTemplate : template))
      : [...templates, nextTemplate]

    setTemplates(nextTemplates)
    setActiveTemplateId(nextTemplate.id)

    await saveAppState({
      templates: nextTemplates.map((template) => ({
        ...template,
        image: persistImageSource(template.image)
      })),
      activeTemplateId: nextTemplate.id,
      classes: storedState?.classes ?? [],
      activeClassId: storedState?.activeClassId ?? '',
      certificates: storedState?.certificates ?? []
    })
  }

  function loadTemplateIntoEditor(template: TemplateItem) {
    setActiveTemplateId(template.id)
    setTemplateDraftName(template.name)
    setTemplateDraftImage(template.image)
    setTemplateDraftConfig(template.config)
  }

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

    if (!file) {
      return
    }

    setTemplateDraftConfig(JSON.parse(await file.text()) as CertificateTemplateConfig)
  }

  return (
    <div className="space-y-5">
      <div className="flex flex-wrap items-center justify-between gap-3">
        <div>
          <p className="text-sm text-muted-foreground">Template Management</p>
          <h2 className="text-2xl font-semibold tracking-normal">毕业证书模板管理</h2>
        </div>
        <div className="flex gap-2">
          <Button
            type="button"
            variant="outline"
            onClick={() => downloadText(JSON.stringify(templateDraftConfig, null, 2), 'certificate-template-config.json')}
          >
            <FileJson />
            导出配置
          </Button>
          <Input
            id="template-config-import"
            type="file"
            accept="application/json,.json"
            className="hidden"
            onChange={importConfig}
          />
          <Button
            type="button"
            variant="outline"
            onClick={() => document.getElementById('template-config-import')?.click()}
          >
            <Upload />
            导入配置
          </Button>
          <Button type="button" onClick={saveTemplate}>
            保存模板
          </Button>
        </div>
      </div>

      <div className="grid gap-5 xl:grid-cols-[minmax(0,1fr)_380px]">
        <Card>
          <CardContent className="p-3">
            <div className="mb-3 flex gap-2">
              <Button
                type="button"
                variant={activeTool === 'image' ? 'default' : 'outline'}
                onClick={() => setActiveTool('image')}
              >
                <ImagePlus />
                照片占位符
              </Button>
              <Button
                type="button"
                variant={activeTool === 'name' ? 'default' : 'outline'}
                onClick={() => setActiveTool('name')}
              >
                <MousePointer2 />
                姓名占位符
              </Button>
            </div>
            <div className="max-h-[calc(100vh-220px)] overflow-auto rounded-md bg-muted p-3">
              <canvas
                ref={canvasRef}
                className="mx-auto block h-auto max-w-full cursor-crosshair rounded-sm border bg-white"
                onPointerDown={handlePointerDown}
                onPointerUp={handlePointerUp}
              />
            </div>
          </CardContent>
        </Card>

        <div className="space-y-4">
          <Card>
            <CardHeader>
              <CardTitle>模板信息</CardTitle>
            </CardHeader>
            <CardContent className="space-y-3">
              <div className="space-y-2">
                <Label htmlFor="template-name">模板名称</Label>
                <Input
                  id="template-name"
                  value={templateDraftName}
                  onChange={(event) => setTemplateDraftName(event.target.value)}
                />
              </div>
              <div className="space-y-2">
                <Label htmlFor="template-image">证书底图</Label>
                <Input
                  id="template-image"
                  type="file"
                  accept="image/jpeg,image/png"
                  onChange={handleTemplateImageChange}
                />
              </div>
              <div className="space-y-2">
                <Label>已有模板</Label>
                {templates.map((template) => (
                  <button
                    key={template.id}
                    type="button"
                    className={cn(
                      'block w-full rounded-md border px-3 py-2 text-left text-sm',
                      activeTemplate?.id === template.id && 'border-primary bg-accent'
                    )}
                    onClick={() => loadTemplateIntoEditor(template)}
                  >
                    {template.name}
                  </button>
                ))}
              </div>
            </CardContent>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle>姓名样式</CardTitle>
            </CardHeader>
            <CardContent className="grid grid-cols-2 gap-3">
              <div className="space-y-2">
                <Label htmlFor="font-family">字体</Label>
                <Input
                  id="font-family"
                  value={templateDraftConfig.textStyle.fontFamily}
                  onChange={(event) =>
                    setTemplateDraftConfig((current) => ({
                      ...current,
                      textStyle: { ...current.textStyle, fontFamily: event.target.value }
                    }))
                  }
                />
              </div>
              <div className="space-y-2">
                <Label htmlFor="font-size">字号</Label>
                <Input
                  id="font-size"
                  type="number"
                  min={12}
                  max={180}
                  value={templateDraftConfig.textStyle.fontSize}
                  onChange={(event) =>
                    setTemplateDraftConfig((current) => ({
                      ...current,
                      textStyle: { ...current.textStyle, fontSize: Number(event.target.value) }
                    }))
                  }
                />
              </div>
              <div className="space-y-2">
                <Label htmlFor="font-color">颜色</Label>
                <Input
                  id="font-color"
                  type="color"
                  value={templateDraftConfig.textStyle.color}
                  onChange={(event) =>
                    setTemplateDraftConfig((current) => ({
                      ...current,
                      textStyle: { ...current.textStyle, color: event.target.value }
                    }))
                  }
                />
              </div>
              <div className="space-y-2">
                <Label htmlFor="font-weight">字重</Label>
                <select
                  id="font-weight"
                  className="h-10 w-full rounded-md border bg-background px-3 text-sm"
                  value={templateDraftConfig.textStyle.fontWeight}
                  onChange={(event) =>
                    setTemplateDraftConfig((current) => ({
                      ...current,
                      textStyle: {
                        ...current.textStyle,
                        fontWeight: event.target.value as CertificateTemplateConfig['textStyle']['fontWeight']
                      }
                    }))
                  }
                >
                  <option value="400">常规</option>
                  <option value="600">半粗</option>
                  <option value="700">粗体</option>
                </select>
              </div>
            </CardContent>
          </Card>
        </div>
      </div>
    </div>
  )
}
