import { useState, useCallback, useEffect, useRef } from 'react'
import { useResizablePanel } from '../../hooks'
import { api, endpoints } from '../../api'
import MediaList from './MediaList'
import VideoPlayer, { type VideoPlayerHandle } from './VideoPlayer'
import CanvasEditor, { type CanvasEditorHandle } from './CanvasEditor'
import AnnotationsSidebar from './AnnotationsSidebar'
import { DetectionClasses } from '../../components'
import { AnnotationSource, AnnotationStatus, MediaType } from '../../types'
import { getClassColor, getClassNameFallback, getPhotoModeSuffix } from '../../class-colors'
import type { Media, AnnotationListItem, Detection } from '../../types'

export default function AnnotationsPage() {
  const [selectedMedia, setSelectedMedia] = useState<Media | null>(null)
  const [currentTime, setCurrentTime] = useState(0)
  const [annotations, setAnnotations] = useState<AnnotationListItem[]>([])
  const [selectedAnnotation, setSelectedAnnotation] = useState<AnnotationListItem | null>(null)
  const [selectedClassNum, setSelectedClassNum] = useState(0)
  const [photoMode, setPhotoMode] = useState(0)
  const [detections, setDetections] = useState<Detection[]>([])
  const leftPanel = useResizablePanel(250, 200, 400)
  const rightPanel = useResizablePanel(200, 150, 350)
  const videoPlayerRef = useRef<VideoPlayerHandle>(null)
  const canvasRef = useRef<CanvasEditorHandle>(null)

  useEffect(() => {
    setDetections([])
    setSelectedAnnotation(null)
    setCurrentTime(0)
  }, [selectedMedia])

  const handleSave = useCallback(async () => {
    if (!selectedMedia || !detections.length) return
    const time = selectedMedia.mediaType === MediaType.Video ? formatTicks(currentTime) : null
    const body = { mediaId: selectedMedia.id, time, detections }

    if (!selectedMedia.path.startsWith('blob:')) {
      try {
        await api.post(endpoints.annotations.annotations(), body)
        const res = await api.get<{ items: AnnotationListItem[] }>(
          endpoints.annotations.annotationsByMedia(selectedMedia.id),
        )
        setAnnotations(res.items)
        return
      } catch {
        // fall through to local save
      }
    }

    const local: AnnotationListItem = {
      id: `local-${crypto.randomUUID()}`,
      mediaId: selectedMedia.id,
      time,
      createdDate: new Date().toISOString(),
      userId: 'local',
      source: AnnotationSource.Manual,
      status: AnnotationStatus.Created,
      isSplit: false,
      splitTile: null,
      detections: [...detections],
    }
    setAnnotations(prev => [...prev, local])
  }, [selectedMedia, detections, currentTime])

  const handleDownload = useCallback(async (ann: AnnotationListItem) => {
    if (!selectedMedia) return

    const txt = ann.detections
      .map(d => `${d.classNum} ${d.centerX.toFixed(6)} ${d.centerY.toFixed(6)} ${d.width.toFixed(6)} ${d.height.toFixed(6)}`)
      .join('\n')
    const stem = `annotation_${new Date().toISOString().replace(/[:.]/g, '-')}`

    const txtBlob = new Blob([txt], { type: 'text/plain' })
    const txtUrl = URL.createObjectURL(txtBlob)
    const txtA = document.createElement('a')
    txtA.href = txtUrl
    txtA.download = `${stem}.txt`
    txtA.click()
    URL.revokeObjectURL(txtUrl)

    // Build the image: video frame or image with rectangles drawn
    const videoEl = videoPlayerRef.current?.getVideoElement() ?? null
    let w = 0, h = 0
    const canvas = document.createElement('canvas')
    if (videoEl && videoEl.videoWidth) {
      w = videoEl.videoWidth
      h = videoEl.videoHeight
      canvas.width = w
      canvas.height = h
      const ctx = canvas.getContext('2d')
      if (ctx) ctx.drawImage(videoEl, 0, 0, w, h)
    } else if (!selectedMedia.path) {
      return
    } else {
      const img = new Image()
      img.crossOrigin = 'anonymous'
      img.src = selectedMedia.path.startsWith('blob:')
        ? selectedMedia.path
        : endpoints.annotations.mediaFile(selectedMedia.id)
      await new Promise(res => { img.onload = res; img.onerror = res })
      w = img.naturalWidth
      h = img.naturalHeight
      canvas.width = w
      canvas.height = h
      const ctx = canvas.getContext('2d')
      if (ctx) ctx.drawImage(img, 0, 0, w, h)
    }

    if (w && h) {
      const ctx = canvas.getContext('2d')
      if (ctx) {
        ctx.lineWidth = 2
        ctx.font = '14px sans-serif'
        const labelH = 17
        const padX = 4
        for (const d of ann.detections) {
          const bx = (d.centerX - d.width / 2) * w
          const by = (d.centerY - d.height / 2) * h
          const bw = d.width * w
          const bh = d.height * h
          const color = getClassColor(d.classNum)

          ctx.strokeStyle = color
          ctx.strokeRect(bx, by, bw, bh)

          const name = d.label || getClassNameFallback(d.classNum)
          const modeSuffix = getPhotoModeSuffix(d.classNum)
          const confSuffix = d.confidence < 0.995 ? ` ${(d.confidence * 100).toFixed(0)}%` : ''
          const label = `${name}${modeSuffix}${confSuffix}`

          const metrics = ctx.measureText(label)
          const labelW = metrics.width + padX * 2
          ctx.fillStyle = color
          ctx.fillRect(bx, Math.max(0, by - labelH), labelW, labelH)
          ctx.fillStyle = '#000'
          ctx.fillText(label, bx + padX, Math.max(13, by - 4))
        }
      }
      canvas.toBlob(blob => {
        if (!blob) return
        const url = URL.createObjectURL(blob)
        const a = document.createElement('a')
        a.href = url
        a.download = `${stem}.png`
        a.click()
        URL.revokeObjectURL(url)
      }, 'image/png')
    }
  }, [selectedMedia])

  const handleAnnotationSelect = useCallback((ann: AnnotationListItem) => {
    setSelectedAnnotation(ann)
    setDetections(ann.detections)
    if (ann.time) {
      const parts = ann.time.split(':').map(Number)
      const seconds = (parts[0] || 0) * 3600 + (parts[1] || 0) * 60 + (parts[2] || 0)
      videoPlayerRef.current?.seek(seconds)
      setCurrentTime(seconds)
    }
  }, [])

  const handleDetectionsChange = useCallback((dets: Detection[]) => {
    setDetections(dets)
  }, [])

  const isVideo = selectedMedia?.mediaType === MediaType.Video

  function formatTicks(seconds: number): string {
    const h = Math.floor(seconds / 3600)
    const m = Math.floor((seconds % 3600) / 60)
    const s = Math.floor(seconds % 60)
    const ms = Math.floor((seconds - Math.floor(seconds)) * 1000)
    return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}.${String(ms).padStart(3, '0')}`
  }

  return (
    <div className="flex h-full">
      {/* Left panel */}
      <div style={{ width: leftPanel.width }} className="bg-az-panel border-r border-az-border flex flex-col shrink-0">
        <MediaList
          selectedMedia={selectedMedia}
          onSelect={setSelectedMedia}
          onAnnotationsLoaded={setAnnotations}
        />
        <DetectionClasses
          selectedClassNum={selectedClassNum}
          onSelect={setSelectedClassNum}
          photoMode={photoMode}
          onPhotoModeChange={setPhotoMode}
        />
      </div>
      <div onMouseDown={leftPanel.onMouseDown} className="w-1 cursor-col-resize bg-az-border hover:bg-az-orange shrink-0" />

      {/* Center - video/canvas */}
      <div className="flex-1 flex flex-col min-h-0">
        {selectedMedia && (
          <div className="bg-az-panel border-b border-az-border px-2 py-1 flex gap-2 items-center shrink-0">
            <button
              onClick={handleSave}
              disabled={!detections.length}
              className="px-2.5 py-1 rounded border border-az-green text-az-green text-[11px] hover:bg-az-green/10 disabled:opacity-40 disabled:cursor-not-allowed"
            >
              Save
            </button>
            <button
              onClick={() => canvasRef.current?.deleteSelected()}
              disabled={!detections.length}
              className="px-2.5 py-1 rounded border border-az-red text-az-red text-[11px] hover:bg-az-red/10 disabled:opacity-40 disabled:cursor-not-allowed"
            >
              Remove
            </button>
            <button
              onClick={() => canvasRef.current?.deleteAll()}
              disabled={!detections.length}
              className="px-2.5 py-1 rounded border border-az-red text-az-red text-[11px] hover:bg-az-red/10 disabled:opacity-40 disabled:cursor-not-allowed"
            >
              Remove All
            </button>
            <span className="text-az-muted text-[10px]">{detections.length} detection{detections.length !== 1 ? 's' : ''}</span>
          </div>
        )}
        {selectedMedia && isVideo && (
          <VideoPlayer
            ref={videoPlayerRef}
            media={selectedMedia}
            onTimeUpdate={setCurrentTime}
          >
            <CanvasEditor
              ref={canvasRef}
              media={selectedMedia}
              annotation={selectedAnnotation}
              detections={detections}
              onDetectionsChange={handleDetectionsChange}
              selectedClassNum={selectedClassNum}
              currentTime={currentTime}
              annotations={annotations}
            />
          </VideoPlayer>
        )}
        {selectedMedia && !isVideo && (
          <CanvasEditor
            ref={canvasRef}
            media={selectedMedia}
            annotation={selectedAnnotation}
            detections={detections}
            onDetectionsChange={handleDetectionsChange}
            selectedClassNum={selectedClassNum}
            currentTime={currentTime}
            annotations={annotations}
          />
        )}
        {!selectedMedia && (
          <div className="flex-1 flex items-center justify-center text-az-muted text-sm">
            Select a media file to start
          </div>
        )}
      </div>

      {/* Right panel */}
      <div onMouseDown={rightPanel.onMouseDown} className="w-1 cursor-col-resize bg-az-border hover:bg-az-orange shrink-0" />
      <div style={{ width: rightPanel.width }} className="bg-az-panel border-l border-az-border flex flex-col shrink-0">
        <AnnotationsSidebar
          media={selectedMedia}
          annotations={annotations}
          selectedAnnotation={selectedAnnotation}
          onSelect={handleAnnotationSelect}
          onAnnotationsUpdate={setAnnotations}
          onDownload={handleDownload}
        />
      </div>
    </div>
  )
}
