import { useState, useEffect, useRef, useCallback } from 'react'
import { format } from 'date-fns'
import { Check, ChevronDown, RotateCcw } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Calendar } from '@/components/ui/calendar'
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from '@/components/ui/collapsible'
import { cn } from '@/lib/utils'
import { formatScanDate, formatTime } from '@/lib/dateUtils'
import { ChangeIcons } from '@/components/shared/ChangeIcons'

interface CompactScanBarProps {
  rootId: number
  initialScanId?: number
  onScanResolved: (scanId: number, startedAt: number) => void
  onNoScan: () => void
}

interface ScanSummary {
  scan_id: number
  started_at: number
  add_count: number | null
  modify_count: number | null
  delete_count: number | null
}

export function CompactScanBar({ rootId, initialScanId, onScanResolved, onNoScan }: CompactScanBarProps) {
  const [pickerOpen, setPickerOpen] = useState(!initialScanId)
  const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined)

  // Calendar scan date highlighting
  const [scanDates, setScanDates] = useState<Set<string>>(new Set())
  const [scanDatesLoaded, setScanDatesLoaded] = useState(false)
  const [displayMonth, setDisplayMonth] = useState<Date>(new Date())

  // Scans for selected date
  const [dateScans, setDateScans] = useState<ScanSummary[]>([])
  const [loadingDateScans, setLoadingDateScans] = useState(false)

  // Resolved scan (the final selection)
  const [resolvedScanId, setResolvedScanId] = useState<number | null>(null)
  const [resolvedStartedAt, setResolvedStartedAt] = useState<number | null>(null)
  const [resolving, setResolving] = useState(false)
  const [isFallback, setIsFallback] = useState(false)

  // Stale request tracking
  const resolveIdRef = useRef(0)
  const scanDatesIdRef = useRef(0)
  const dateScansIdRef = useRef(0)

  // ── Fetch scan dates for calendar highlighting ─────────────────────
  // Fetches current, previous, and next months in parallel so outside
  // dates (from adjacent months visible in the calendar) are covered.
  const fetchScanDates = useCallback(
    async (month: Date) => {
      const currentId = ++scanDatesIdRef.current
      try {
        const months = [
          new Date(month.getFullYear(), month.getMonth() - 1, 1),
          month,
          new Date(month.getFullYear(), month.getMonth() + 1, 1),
        ]

        const results = await Promise.all(
          months.map(async (m) => {
            const params = new URLSearchParams({
              root_id: rootId.toString(),
              year: m.getFullYear().toString(),
              month: (m.getMonth() + 1).toString(),
            })
            const response = await fetch(`/api/scans/scan_dates?${params}`)
            if (response.ok) {
              const data = (await response.json()) as { dates: string[] }
              return data.dates
            }
            return []
          })
        )

        if (currentId !== scanDatesIdRef.current) return
        setScanDates(new Set(results.flat()))
        setScanDatesLoaded(true)
      } catch {
        if (currentId !== scanDatesIdRef.current) return
      }
    },
    [rootId]
  )

  // ── Fetch scans for a specific date ────────────────────────────────
  const fetchScansForDate = useCallback(
    async (date: Date, autoSelectScanId?: number) => {
      const currentId = ++dateScansIdRef.current
      setLoadingDateScans(true)

      const dateStr = format(date, 'yyyy-MM-dd')

      try {
        const params = new URLSearchParams({
          root_id: rootId.toString(),
          date: dateStr,
        })
        const response = await fetch(`/api/scans/by_date?${params}`)
        if (currentId !== dateScansIdRef.current) return

        if (response.ok) {
          const data = (await response.json()) as { scans: ScanSummary[] }

          if (data.scans.length > 0) {
            setDateScans(data.scans)
            setIsFallback(false)
            const target = autoSelectScanId
              ? data.scans.find((s) => s.scan_id === autoSelectScanId) ?? data.scans[0]
              : data.scans[0]
            setResolvedScanId(target.scan_id)
            setResolvedStartedAt(target.started_at)
            onScanResolved(target.scan_id, target.started_at)
          } else {
            setDateScans([])
            const resolveParams = new URLSearchParams({
              root_id: rootId.toString(),
              date: dateStr,
            })
            const resolveResponse = await fetch(`/api/scans/resolve?${resolveParams}`)
            if (currentId !== dateScansIdRef.current) return

            if (resolveResponse.ok) {
              const resolveData = (await resolveResponse.json()) as {
                scan_id: number
                started_at: number
              }
              setResolvedScanId(resolveData.scan_id)
              setResolvedStartedAt(resolveData.started_at)
              setIsFallback(true)
              onScanResolved(resolveData.scan_id, resolveData.started_at)
            } else {
              setResolvedScanId(null)
              setResolvedStartedAt(null)
              onNoScan()
            }
          }
        }
      } catch {
        if (currentId !== dateScansIdRef.current) return
        onNoScan()
      } finally {
        if (currentId === dateScansIdRef.current) {
          setLoadingDateScans(false)
        }
      }
    },
    [rootId, onScanResolved, onNoScan]
  )

  // ── Jump to latest scan ────────────────────────────────────────────
  const jumpToLatest = useCallback(async () => {
    const currentId = ++resolveIdRef.current
    setResolving(true)

    try {
      const params = new URLSearchParams({ root_id: rootId.toString() })
      const response = await fetch(`/api/scans/resolve?${params}`)

      if (currentId !== resolveIdRef.current) return

      if (response.ok) {
        const data = (await response.json()) as { scan_id: number; started_at: number }
        const scanDate = new Date(data.started_at * 1000)

        setDisplayMonth(new Date(scanDate.getFullYear(), scanDate.getMonth(), 1))
        setSelectedDate(new Date(scanDate.getFullYear(), scanDate.getMonth(), scanDate.getDate()))

        setResolvedScanId(data.scan_id)
        setResolvedStartedAt(data.started_at)
        setIsFallback(false)
        onScanResolved(data.scan_id, data.started_at)

        const monthDate = new Date(scanDate.getFullYear(), scanDate.getMonth(), 1)
        fetchScanDates(monthDate)
        const dayDate = new Date(scanDate.getFullYear(), scanDate.getMonth(), scanDate.getDate())
        fetchScansForDate(dayDate, data.scan_id)
      } else {
        setResolvedScanId(null)
        setResolvedStartedAt(null)
        setSelectedDate(undefined)
        setDateScans([])
        onNoScan()
      }
    } catch {
      if (currentId !== resolveIdRef.current) return
      setResolvedScanId(null)
      setResolvedStartedAt(null)
      onNoScan()
    } finally {
      if (currentId === resolveIdRef.current) {
        setResolving(false)
      }
    }
  }, [rootId, onScanResolved, onNoScan, fetchScanDates, fetchScansForDate])

  // ── Jump to a specific scan by ID ──────────────────────────────────
  const jumpToScan = useCallback(async (scanId: number) => {
    const currentId = ++resolveIdRef.current
    setResolving(true)

    try {
      const params = new URLSearchParams({ scan_id: scanId.toString() })
      const response = await fetch(`/api/scans/resolve?${params}`)

      if (currentId !== resolveIdRef.current) return

      if (response.ok) {
        const data = (await response.json()) as { scan_id: number; started_at: number }
        const scanDate = new Date(data.started_at * 1000)

        setDisplayMonth(new Date(scanDate.getFullYear(), scanDate.getMonth(), 1))
        setSelectedDate(new Date(scanDate.getFullYear(), scanDate.getMonth(), scanDate.getDate()))

        setResolvedScanId(data.scan_id)
        setResolvedStartedAt(data.started_at)
        setIsFallback(false)
        onScanResolved(data.scan_id, data.started_at)

        const monthDate = new Date(scanDate.getFullYear(), scanDate.getMonth(), 1)
        fetchScanDates(monthDate)
        const dayDate = new Date(scanDate.getFullYear(), scanDate.getMonth(), scanDate.getDate())
        fetchScansForDate(dayDate, data.scan_id)
      } else {
        // Scan not found, fall back to latest
        jumpToLatest()
      }
    } catch {
      if (currentId !== resolveIdRef.current) return
      jumpToLatest()
    } finally {
      if (currentId === resolveIdRef.current) {
        setResolving(false)
      }
    }
  }, [onScanResolved, fetchScanDates, fetchScansForDate, jumpToLatest])

  // ── Initialize on mount / rootId change ────────────────────────────
  useEffect(() => {
    setScanDates(new Set())
    setScanDatesLoaded(false)
    setDateScans([])
    setSelectedDate(undefined)
    setIsFallback(false)
    if (initialScanId) {
      jumpToScan(initialScanId)
    } else {
      jumpToLatest()
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [rootId])

  // ── Jump to a specific scan when initialScanId changes (e.g., deep-link from Trends)
  useEffect(() => {
    if (initialScanId && initialScanId !== resolvedScanId) {
      jumpToScan(initialScanId)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [initialScanId])

  // ── Fetch scan dates when calendar month changes ───────────────────
  useEffect(() => {
    fetchScanDates(displayMonth)
  }, [displayMonth, fetchScanDates])

  // ── Handlers ───────────────────────────────────────────────────────
  const handleDateSelect = (date: Date | undefined) => {
    if (!date) return
    setSelectedDate(date)
    fetchScansForDate(date)
  }

  const handleScanClick = (scan: ScanSummary) => {
    setResolvedScanId(scan.scan_id)
    setResolvedStartedAt(scan.started_at)
    setIsFallback(false)
    onScanResolved(scan.scan_id, scan.started_at)
  }

  const handleMonthChange = (month: Date) => {
    setDisplayMonth(month)
  }

  // Disable + line-through dates without scans (only after scan dates have loaded)
  const noScanMatcher = scanDatesLoaded
    ? (date: Date) => !scanDates.has(format(date, 'yyyy-MM-dd'))
    : undefined

  // ── Render ─────────────────────────────────────────────────────────
  return (
    <Collapsible open={pickerOpen} onOpenChange={setPickerOpen}>
      <div className="border border-border rounded-lg bg-muted/30">
        {/* Header row: scan info + collapse toggle + Latest button */}
        <div className="flex items-center gap-1.5 px-3 py-2">
          <CollapsibleTrigger asChild>
            <button className="flex items-center gap-2 min-w-0 text-left border-none bg-transparent p-0 cursor-pointer">
              <ChevronDown className={cn("h-4 w-4 flex-shrink-0 text-muted-foreground transition-transform", !pickerOpen && "-rotate-90")} />
              {resolvedScanId && resolvedStartedAt ? (
                <p className="text-sm font-medium truncate">
                  Scan #{resolvedScanId} &mdash; {formatScanDate(resolvedStartedAt)} at {formatTime(resolvedStartedAt)}
                </p>
              ) : resolving ? (
                <p className="text-sm font-medium text-muted-foreground animate-pulse">Resolving...</p>
              ) : (
                <p className="text-sm font-medium text-muted-foreground">No completed scans</p>
              )}
            </button>
          </CollapsibleTrigger>

          <Button
            variant="ghost"
            size="sm"
            className="h-6 w-6 p-0 flex-shrink-0 text-primary hover:text-primary"
            onClick={jumpToLatest}
            disabled={resolving}
            title="Reset to latest scan"
          >
            <RotateCcw className="h-3.5 w-3.5" />
          </Button>
        </div>

        {/* Collapsible picker: calendar + scan list side by side */}
        <CollapsibleContent>
          <div className="border-t border-border">
            <div className="flex overflow-hidden">
              {/* Calendar */}
              <div className="border-r border-border shrink-0">
                <Calendar
                  mode="single"
                  captionLayout="dropdown"
                  selected={selectedDate}
                  onSelect={handleDateSelect}
                  month={displayMonth}
                  onMonthChange={handleMonthChange}
                  disabled={noScanMatcher}
                  modifiers={{
                    noScan: noScanMatcher ?? [],
                  }}
                  modifiersClassNames={{
                    noScan: '[&>button]:line-through opacity-100',
                  }}
                  className="p-2 [--cell-size:1.625rem]"
                  classNames={{
                    month: 'flex w-full flex-col gap-2',
                    week: 'mt-1 flex w-full',
                  }}
                />
              </div>

              {/* Scan list */}
              <div className="flex-1 min-w-0 flex flex-col">
                <div className="px-3 py-2 border-b border-border">
                  <p className="text-xs font-medium text-muted-foreground truncate">
                    {selectedDate ? `Scans on ${format(selectedDate, 'MMM d, yyyy')}` : 'Select a date'}
                  </p>
                </div>

                <div className="flex-1 overflow-y-auto max-h-64 px-2 py-1">
                  {!selectedDate ? (
                    <p className="text-xs text-muted-foreground px-1 py-6 text-center">
                      Click a date to see scans
                    </p>
                  ) : loadingDateScans && dateScans.length === 0 && !isFallback ? (
                    <p className="text-xs text-muted-foreground px-1 py-6 text-center animate-pulse">
                      Loading...
                    </p>
                  ) : dateScans.length > 0 ? (
                    <div className="space-y-0.5">
                      {dateScans.map((scan) => (
                        <button
                          key={scan.scan_id}
                          className={cn(
                            'w-full flex items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors overflow-hidden',
                            'hover:bg-accent',
                            scan.scan_id === resolvedScanId
                              ? 'bg-accent font-medium'
                              : ''
                          )}
                          onClick={() => handleScanClick(scan)}
                        >
                          <span className="shrink-0 w-3.5">
                            {scan.scan_id === resolvedScanId && (
                              <Check className="h-3 w-3" />
                            )}
                          </span>
                          <div className="min-w-0">
                            <div className="flex items-center gap-1.5 whitespace-nowrap">
                              <span className="text-xs font-medium">#{scan.scan_id}</span>
                              <span className="text-xs text-muted-foreground">
                                {formatTime(scan.started_at)}
                              </span>
                            </div>
                            <div className="text-xs">
                              <ChangeIcons add={scan.add_count} modify={scan.modify_count} del={scan.delete_count} />
                              {!scan.add_count && !scan.modify_count && !scan.delete_count && (
                                <span className="text-muted-foreground">no changes</span>
                              )}
                            </div>
                          </div>
                        </button>
                      ))}
                    </div>
                  ) : isFallback && resolvedScanId && resolvedStartedAt ? (
                    <div className="px-1 py-4 text-xs text-muted-foreground space-y-1">
                      <p>No scans on this date.</p>
                      <p>
                        Showing nearest:{' '}
                        <span className="font-medium text-foreground">#{resolvedScanId}</span> from{' '}
                        {formatScanDate(resolvedStartedAt)}
                      </p>
                    </div>
                  ) : (
                    <p className="text-xs text-muted-foreground px-1 py-6 text-center">
                      No scans found
                    </p>
                  )}
                </div>
              </div>
            </div>
          </div>
        </CollapsibleContent>
      </div>
    </Collapsible>
  )
}
