import { useState, useEffect, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { api, endpoints, authenticatedApiUrl } from '../../api'
import { useDebounce } from '../../hooks'
import { useFlight } from '../../components'
import { useSavedAnnotations } from '../../components/SavedAnnotationsContext'
import CanvasEditor from '../annotations/CanvasEditor'
import { recaptureThumbnails } from '../annotations/thumbnail'
import type { SavedDetection } from '../../components/SavedAnnotationsContext'
import type {
  DatasetItem,
  PaginatedResponse,
  ClassDistributionItem,
  AnnotationListItem,
  Detection,
  Media,
} from '../../types'
import { AnnotationSource, AnnotationStatus } from '../../types'
import DatasetLeftPanel from './DatasetLeftPanel'
import DatasetFilterBar from './DatasetFilterBar'
import DatasetTile, { type DatasetCard } from './DatasetTile'
import DatasetStatusBar from './DatasetStatusBar'

type Tab = 'annotations' | 'editor' | 'distribution'

export default function DatasetPage() {
  const { t } = useTranslation()
  const { selectedFlight } = useFlight()
  const { saved: savedAnnotations, removeSaved, replaceGroup, updateStatus } = useSavedAnnotations()

  const [items, setItems] = useState<DatasetItem[]>([])
  const [totalCount, setTotalCount] = useState(0)
  const [page, setPage] = useState(1)
  const [pageSize] = useState(20)
  const [fromDate, setFromDate] = useState('')
  const [toDate, setToDate] = useState('')
  const [statusFilter, setStatusFilter] = useState<AnnotationStatus | null>(null)
  const [objectsOnly, setObjectsOnly] = useState(false)
  const [search, setSearch] = useState('')
  const debouncedSearch = useDebounce(search, 400)
  const [selectedClassNum, setSelectedClassNum] = useState(0)
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
  const [tab, setTab] = useState<Tab>('annotations')
  const [editorAnnotation, setEditorAnnotation] = useState<AnnotationListItem | null>(null)
  const [editorDetections, setEditorDetections] = useState<Detection[]>([])
  const [distribution, setDistribution] = useState<ClassDistributionItem[]>([])
  const [editorFullFrame, setEditorFullFrame] = useState<string>('')
  const [editorLocalGroupId, setEditorLocalGroupId] = useState<string | null>(null)
  const [editorSaving, setEditorSaving] = useState(false)

  const fetchItems = useCallback(async () => {
    const params = new URLSearchParams({ page: String(page), pageSize: String(pageSize) })
    if (fromDate) params.set('fromDate', fromDate)
    if (toDate) params.set('toDate', toDate)
    if (selectedFlight) params.set('flightId', selectedFlight.id)
    if (statusFilter !== null) params.set('status', String(statusFilter))
    if (selectedClassNum) params.set('classNum', String(selectedClassNum))
    if (objectsOnly) params.set('hasDetections', 'true')
    if (debouncedSearch) params.set('name', debouncedSearch)
    try {
      const res = await api.get<PaginatedResponse<DatasetItem>>(endpoints.annotations.dataset(params.toString()))
      setItems(res.items)
      setTotalCount(res.totalCount)
    } catch {}
  }, [page, pageSize, fromDate, toDate, selectedFlight, statusFilter, selectedClassNum, objectsOnly, debouncedSearch])

  useEffect(() => { fetchItems() }, [fetchItems])

  const cards = useMemo<DatasetCard[]>(() => {
    const localCards: DatasetCard[] = savedAnnotations
      .filter(sd => {
        if (selectedFlight && sd.flightId && sd.flightId !== selectedFlight.id) return false
        if (statusFilter !== null && sd.status !== statusFilter) return false
        if (selectedClassNum && sd.detection.classNum !== selectedClassNum) return false
        if (debouncedSearch && !sd.mediaName.toLowerCase().includes(debouncedSearch.toLowerCase())) return false
        if (fromDate && sd.createdDate < fromDate) return false
        if (toDate && sd.createdDate > `${toDate}T23:59:59`) return false
        return true
      })
      .map(sd => ({
        annotationId: sd.id,
        imageName: sd.mediaName,
        status: sd.status,
        createdDate: sd.createdDate,
        thumbnailUrl: sd.thumbnail,
        isSeed: false,
        isLocal: true,
        detections: [sd.detection],
        mediaId: sd.mediaId,
        time: sd.time,
        fullFrame: sd.fullFrame,
        annotationLocalId: sd.annotationLocalId,
      }))

    const remoteCards: DatasetCard[] = items.map(item => ({
      annotationId: item.annotationId,
      imageName: item.imageName,
      status: item.status,
      createdDate: item.createdDate,
      thumbnailUrl: authenticatedApiUrl(endpoints.annotations.annotationThumbnail(item.annotationId)),
      isSeed: item.isSeed,
      isLocal: false,
    }))

    return [...localCards, ...remoteCards]
  }, [savedAnnotations, items, selectedFlight, statusFilter, selectedClassNum, debouncedSearch, fromDate, toDate])

  const handleDoubleClick = async (card: DatasetCard) => {
    if (card.isLocal && card.detections && card.mediaId) {
      setEditorAnnotation({
        id: card.annotationId,
        mediaId: card.mediaId,
        time: card.time ?? null,
        createdDate: card.createdDate,
        userId: 'local',
        source: AnnotationSource.Manual,
        status: card.status,
        isSplit: false,
        splitTile: null,
        detections: card.detections,
      })
      setEditorDetections(card.detections)
      setEditorFullFrame(card.fullFrame ?? '')
      setEditorLocalGroupId(card.annotationLocalId ?? null)
      setTab('editor')
      return
    }
    setEditorFullFrame('')
    setEditorLocalGroupId(null)
    try {
      const ann = await api.get<AnnotationListItem>(endpoints.annotations.datasetItem(card.annotationId))
      setEditorAnnotation(ann)
      setEditorDetections(ann.detections)
      setTab('editor')
    } catch {}
  }

  const handleEditorSave = async () => {
    if (!editorAnnotation) return
    setEditorSaving(true)
    try {
      if (editorLocalGroupId) {
        const existing = savedAnnotations.find(s => s.annotationLocalId === editorLocalGroupId)
        const thumbs = await recaptureThumbnails(editorFullFrame, editorDetections)
        const now = new Date().toISOString()
        const replacement: SavedDetection[] = editorDetections.map((d, i) => ({
          id: `${editorLocalGroupId}:${d.id ?? i}`,
          annotationLocalId: editorLocalGroupId,
          mediaId: editorAnnotation.mediaId,
          mediaName: existing?.mediaName ?? '',
          thumbnail: thumbs[i] ?? '',
          fullFrame: editorFullFrame,
          status: AnnotationStatus.Edited,
          source: existing?.source ?? AnnotationSource.Manual,
          createdDate: existing?.createdDate ?? now,
          detection: d,
          time: editorAnnotation.time,
          flightId: existing?.flightId ?? null,
        }))
        replaceGroup(editorLocalGroupId, replacement)
      }
      setTab('annotations')
    } finally {
      setEditorSaving(false)
    }
  }

  const handleEditorCancel = () => {
    if (editorAnnotation) setEditorDetections(editorAnnotation.detections)
    setTab('annotations')
  }

  const handleValidate = async () => {
    if (selectedIds.size === 0) return
    const allIds = Array.from(selectedIds)
    const localIds = allIds.filter(id => id.startsWith('saved-') || id.startsWith('local-'))
    const backendIds = allIds.filter(id => !id.startsWith('saved-') && !id.startsWith('local-'))

    if (backendIds.length > 0) {
      try {
        await api.post(endpoints.annotations.datasetBulkStatus(), {
          annotationIds: backendIds,
          status: AnnotationStatus.Validated,
        })
      } catch {}
    }
    if (localIds.length > 0) {
      updateStatus(localIds, AnnotationStatus.Validated)
    }
    setSelectedIds(new Set())
    setPage(1)
    fetchItems()
  }

  useEffect(() => {
    api.get<ClassDistributionItem[]>(endpoints.annotations.datasetClassDistribution())
      .then(setDistribution)
      .catch(() => {})
  }, [])

  const classCounts = useMemo(() => {
    const m: Record<number, number> = {}
    for (const d of distribution) m[d.classNum] = d.count
    return m
  }, [distribution])

  const maxDistCount = useMemo(
    () => Math.max(...distribution.map(d => d.count), 1),
    [distribution],
  )
  const totalPages = Math.ceil(totalCount / pageSize)
  const relevantSavedCount = useMemo(() => {
    if (!selectedFlight) return savedAnnotations.length
    return savedAnnotations.filter(sd => !sd.flightId || sd.flightId === selectedFlight.id).length
  }, [savedAnnotations, selectedFlight])
  const grandTotal = totalCount + relevantSavedCount
  const validatedCount = useMemo(
    () => cards.filter(c => c.status === AnnotationStatus.Validated).length,
    [cards],
  )

  const firstSelectedName = useMemo(() => {
    const firstId = selectedIds.values().next().value
    if (!firstId) return null
    return cards.find(c => c.annotationId === firstId)?.imageName ?? null
  }, [selectedIds, cards])

  const editorMedia: Media | null = editorAnnotation ? {
    id: editorAnnotation.mediaId, name: '', path: editorFullFrame, mediaType: 1, mediaStatus: 0,
    duration: null, annotationCount: 0, waypointId: null, userId: '',
  } : null

  return (
    <div className="flex-1 flex overflow-hidden p-3 gap-3 h-full">
      <DatasetLeftPanel
        selectedClassNum={selectedClassNum}
        onSelectClass={setSelectedClassNum}
        classCounts={classCounts}
        objectsOnly={objectsOnly}
        onObjectsOnlyChange={setObjectsOnly}
        search={search}
        onSearchChange={setSearch}
        totalCount={grandTotal}
        validatedCount={validatedCount}
      />

      <main className="flex-1 min-w-0 flex flex-col gap-3">
        <DatasetFilterBar
          fromDate={fromDate}
          toDate={toDate}
          onFromDateChange={setFromDate}
          onToDateChange={setToDate}
          statusFilter={statusFilter}
          onStatusFilterChange={s => { setStatusFilter(s); setPage(1) }}
          flightName={selectedFlight?.name ?? null}
          shownCount={cards.length}
          totalCount={grandTotal}
        />

        <div className="bracket panel relative flex-1 flex flex-col min-h-0 overflow-hidden">
          <span className="br" />

          {/* Tab strip */}
          <div className="flex items-center px-2 border-b border-border-hair shrink-0">
            <button
              type="button"
              onClick={() => setTab('annotations')}
              className={`tab ${tab === 'annotations' ? 'active' : ''}`}
            >
              <span>{t('dataset.annotations')}</span>
              <span
                className={`ml-1.5 px-1.5 py-px text-[10px] font-mono border rounded-[2px] tabular-nums ${
                  tab === 'annotations'
                    ? 'text-accent-amber border-accent-amber'
                    : 'text-text-muted border-border-hair'
                }`}
              >
                {cards.length}
              </span>
            </button>
            <button
              type="button"
              onClick={() => setTab('editor')}
              className={`tab ${tab === 'editor' ? 'active' : ''}`}
            >
              <span>{t('dataset.editor')}</span>
              <span
                className={`ml-1.5 px-1.5 py-px text-[10px] font-mono border rounded-[2px] tabular-nums ${
                  tab === 'editor'
                    ? 'text-accent-amber border-accent-amber'
                    : 'text-text-muted border-border-hair'
                }`}
              >
                {editorAnnotation ? editorDetections.length : '—'}
              </span>
            </button>
            <button
              type="button"
              onClick={() => setTab('distribution')}
              className={`tab ${tab === 'distribution' ? 'active' : ''}`}
            >
              <span>{t('dataset.classDistribution')}</span>
            </button>

            <div
              className="ml-auto flex items-center gap-2 px-2 micro"
              style={{ color: 'var(--text-muted)' }}
            >
              <span className="live-dot" />
              <span>{t('dataset.liveSync')}</span>
            </div>
          </div>

          {/* Content */}
          {tab === 'annotations' && (
            <div className="flex-1 overflow-y-auto p-2">
              <div
                className="grid gap-2"
                style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(170px, 1fr))' }}
              >
                {cards.map(card => (
                  <DatasetTile
                    key={card.annotationId}
                    card={card}
                    isSelected={selectedIds.has(card.annotationId)}
                    onClick={e => {
                      if (e.ctrlKey || e.metaKey) {
                        setSelectedIds(prev => {
                          const n = new Set(prev)
                          if (n.has(card.annotationId)) n.delete(card.annotationId)
                          else n.add(card.annotationId)
                          return n
                        })
                      } else {
                        setSelectedIds(new Set([card.annotationId]))
                      }
                    }}
                    onDoubleClick={() => handleDoubleClick(card)}
                    onContextMenu={e => {
                      if (!card.isLocal) return
                      e.preventDefault()
                      removeSaved(card.annotationId)
                    }}
                    onEditClick={() => handleDoubleClick(card)}
                  />
                ))}
              </div>
              {cards.length === 0 && (
                <div className="text-center text-text-muted text-xs py-8">{t('common.noData')}</div>
              )}
              {totalPages > 1 && (
                <div className="flex justify-center items-center gap-3 py-3">
                  <button
                    type="button"
                    className="btn btn-ghost"
                    onClick={() => setPage(p => Math.max(1, p - 1))}
                    disabled={page === 1}
                  >
                    Prev
                  </button>
                  <span className="mono text-[12px] text-text-primary tabular-nums">
                    {page} / {totalPages}
                  </span>
                  <button
                    type="button"
                    className="btn btn-ghost"
                    onClick={() => setPage(p => Math.min(totalPages, p + 1))}
                    disabled={page === totalPages}
                  >
                    Next
                  </button>
                </div>
              )}
            </div>
          )}

          {tab === 'editor' && editorMedia && editorAnnotation && (
            <div className="flex-1 min-h-0 relative overflow-hidden">
              <div className="absolute inset-0 flex flex-col">
                <div className="bg-surface-1 border-b border-border-hair px-3 py-2 flex gap-2 items-center shrink-0">
                  <button
                    type="button"
                    className="btn btn-primary"
                    onClick={handleEditorSave}
                    disabled={editorSaving || (!editorLocalGroupId && editorDetections.length === 0)}
                  >
                    {editorSaving ? 'Saving…' : t('common.save')}
                  </button>
                  <button
                    type="button"
                    className="btn btn-ghost"
                    onClick={handleEditorCancel}
                    disabled={editorSaving}
                  >
                    {t('common.cancel')}
                  </button>
                  <span className="micro" style={{ color: 'var(--text-muted)' }}>
                    {editorDetections.length} detection{editorDetections.length !== 1 ? 's' : ''}
                  </span>
                  {!editorLocalGroupId && (
                    <span className="micro ml-auto" style={{ color: 'var(--text-muted)' }}>
                      remote save not wired yet
                    </span>
                  )}
                </div>
                <div className="flex-1 min-h-0 relative">
                  <div className="absolute inset-0">
                    <CanvasEditor
                      media={editorMedia}
                      annotation={editorAnnotation}
                      detections={editorDetections}
                      onDetectionsChange={setEditorDetections}
                      selectedClassNum={selectedClassNum}
                      currentTime={0}
                      annotations={[]}
                    />
                  </div>
                </div>
              </div>
            </div>
          )}

          {tab === 'distribution' && (
            <div className="flex-1 overflow-y-auto">
              {distribution.map(d => {
                const pct = (d.count / maxDistCount) * 100
                return (
                  <div
                    key={d.classNum}
                    className="relative flex items-center h-8 border-b border-border-hair px-3 gap-3"
                  >
                    <div
                      className="absolute inset-y-0 left-0 pointer-events-none"
                      style={{ width: `${pct}%`, backgroundColor: d.color, opacity: 0.18 }}
                    />
                    <span className="swatch shrink-0 relative" style={{ background: d.color }} />
                    <span className="relative text-[12px] text-text-primary truncate">{d.label}</span>
                    <span className="relative ml-auto mono text-[12px] text-text-primary tabular-nums">
                      {d.count.toLocaleString()}
                    </span>
                  </div>
                )
              })}
              {distribution.length === 0 && (
                <div className="text-center text-text-muted text-xs py-8">{t('common.noData')}</div>
              )}
            </div>
          )}
        </div>

        <DatasetStatusBar
          selectedCount={selectedIds.size}
          totalShown={cards.length}
          firstSelectedName={firstSelectedName}
          canValidate={selectedIds.size > 0}
          onValidate={handleValidate}
        />
      </main>
    </div>
  )
}
