'use client'

import { useState } from 'react'
import { toast } from 'sonner'
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { VEHICLE_PHOTO_SIDES, type VehiclePhotoSide } from '@/lib/domain/pilot'
import type { UnitPhoto, UnitPhotoLogEntry, UnitPhotos } from '@/lib/data/pilot-units'

/**
 * The four side photos of a pilot unit (Nash, 2026-09-19). Shared by the
 * Pilot Dispatch Dashboard (Units) and the Pilot Car Driver app (My Pilot
 * Car); each page passes its own API route and mode.
 *
 *   drop / click on a slot   uploads; dropping on a filled slot OVERWRITES it
 *   mobile mode              tapping a slot opens the phone's own sheet —
 *                            take a photo with the camera or choose from
 *                            the library (accept="image/*"); drop still works
 *   click a photo            opens it full size with who uploaded it and when,
 *                            plus Replace and Remove
 *   Photo history            every upload / replacement / removal, by whom
 */

const fmt = (iso: string) => new Date(iso).toLocaleString()
const ACCEPT = 'image/*'

async function upload(apiUrl: string, unitId: string, side: VehiclePhotoSide, file: File) {
  const fd = new FormData()
  fd.set('unit_id', unitId)
  fd.set('side', side)
  fd.set('file', file)
  const r = await fetch(apiUrl, { method: 'POST', body: fd })
  const json = await r.json().catch(() => ({}))
  if (!r.ok) throw new Error(json.error ?? 'Upload failed.')
  return json as { action: 'uploaded' | 'replaced'; photo: UnitPhoto; logEntry: UnitPhotoLogEntry }
}

export function UnitPhotoGrid({ unitId, unitLabel, photos, onChanged, apiUrl = '/api/pd/unit-photos', mobile = false }: { unitId: string; unitLabel: string; photos: UnitPhotos; onChanged: (side: VehiclePhotoSide, present: boolean) => void; /** This page's own route. */ apiUrl?: string; /** Phone-first wording: tap = camera or library. */ mobile?: boolean }) {
  // Local copy of this unit's photos and history: updated from the server's
  // reply, so the page does not need a full refresh after every change.
  const [local, setLocal] = useState<{ photos: Record<string, UnitPhoto>; log: UnitPhotoLogEntry[] }>({ photos: {}, log: [] })
  const [removed, setRemoved] = useState<Set<string>>(new Set())
  const photoFor = (side: VehiclePhotoSide): UnitPhoto | undefined => (removed.has(side) ? undefined : local.photos[side] ?? photos.photos[`${unitId}:${side}`])
  const [open, setOpen] = useState<VehiclePhotoSide | null>(null)
  const [busy, setBusy] = useState<VehiclePhotoSide | null>(null)
  const [over, setOver] = useState<VehiclePhotoSide | null>(null)
  const [showLog, setShowLog] = useState(false)
  const log: UnitPhotoLogEntry[] = [...local.log, ...(photos.log[unitId] ?? [])]

  async function put(side: VehiclePhotoSide, file: File | undefined) {
    if (!file) return
    setBusy(side)
    try {
      const r = await upload(apiUrl, unitId, side, file)
      toast.success(r.action === 'replaced' ? `${side} photo replaced.` : `${side} photo uploaded.`)
      setLocal((l) => ({ photos: { ...l.photos, [side]: r.photo }, log: [r.logEntry, ...l.log] }))
      setRemoved((set) => { const n = new Set(set); n.delete(side); return n })
      onChanged(side, true)
    } catch (e) {
      toast.error(e instanceof Error ? e.message : 'Upload failed.')
    } finally {
      setBusy(null)
    }
  }
  async function remove(side: VehiclePhotoSide) {
    setBusy(side)
    try {
      const r = await fetch(apiUrl, { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ unit_id: unitId, side }) })
      const json = await r.json().catch(() => ({}))
      if (!r.ok) throw new Error(json.error ?? 'Could not remove the photo.')
      toast.success(`${side} photo removed.`)
      setLocal((l) => { const photos = { ...l.photos }; delete photos[side]; return { photos, log: json.logEntry ? [json.logEntry, ...l.log] : l.log } })
      setRemoved((set) => new Set(set).add(side))
      setOpen(null)
      onChanged(side, false)
    } catch (e) {
      toast.error(e instanceof Error ? e.message : 'Could not remove the photo.')
    } finally {
      setBusy(null)
    }
  }

  const current: UnitPhoto | undefined = open ? photoFor(open) : undefined
  return (
    <>
      <div className="mt-3 grid grid-cols-4 gap-2">
        {VEHICLE_PHOTO_SIDES.map((side) => {
          const photo = photoFor(side)
          const isOver = over === side
          return (
            <label
              key={side}
              title={photo ? `${side} — uploaded by ${photo.uploadedBy} ${fmt(photo.uploadedAt)}. ${mobile ? 'Tap' : 'Click'} to view; drop a new image to overwrite.` : mobile ? `Tap to take the ${side.toLowerCase()} photo or choose it from your library` : `Drop or choose the ${side.toLowerCase()} photo`}
              onDragOver={(e) => { e.preventDefault(); setOver(side) }}
              onDragLeave={() => setOver(null)}
              onDrop={(e) => { e.preventDefault(); setOver(null); void put(side, e.dataTransfer.files?.[0]) }}
              onClick={(e) => { if (photo) { e.preventDefault(); setOpen(side) } }}
              className={`relative aspect-[4/3] cursor-pointer overflow-hidden rounded-lg text-[10px] font-semibold ring-1 ring-inset transition ${
                isOver ? 'bg-amber-50 ring-2 ring-amber-brand' : photo ? 'ring-navy-100' : 'bg-white text-slate-body ring-dashed ring-line hover:text-ink'
              }`}
            >
              {photo?.url ? (
                // eslint-disable-next-line @next/next/no-img-element
                <img src={photo.url} alt={`${unitLabel} ${side}`} className="h-full w-full object-cover" />
              ) : photo ? (
                <span className="flex h-full items-center justify-center">📷 {side}</span>
              ) : (
                <span className="flex h-full flex-col items-center justify-center gap-0.5 px-1 text-center">
                  <span>+ {side}</span>
                  <span className="text-[9px] font-normal text-slate-body/70">{mobile ? 'tap · camera or library' : 'drop or click'}</span>
                </span>
              )}
              {photo && <span className="absolute inset-x-0 bottom-0 bg-navy-950/70 px-1 py-0.5 text-[9px] font-bold text-white">{side}</span>}
              {busy === side && <span className="absolute inset-0 flex items-center justify-center bg-white/70 text-[10px] font-bold text-navy-900">Uploading…</span>}
              {!photo && <input type="file" accept={ACCEPT} className="hidden" onChange={(e) => { void put(side, e.target.files?.[0]); e.target.value = '' }} />}
            </label>
          )
        })}
      </div>
      {!photos.available && <p className="mt-1.5 text-[11px] text-warn">Photo uploads need database migration 0023 (pilot unit photos).</p>}

      {/* who did what */}
      <div className="mt-2 flex items-center justify-between text-[11px]">
        <span className="text-slate-body">
          {log[0] ? `Last update: ${log[0].actor} ${log[0].action} the ${log[0].side.toLowerCase()} photo · ${fmt(log[0].at)}` : 'No photo changes yet.'}
        </span>
        {log.length > 0 && <button onClick={() => setShowLog((v) => !v)} className="font-bold text-info hover:underline">{showLog ? 'Hide' : 'Photo history'} ({log.length})</button>}
      </div>
      {showLog && (
        <ul className="mt-1.5 divide-y divide-line rounded-lg border border-line text-[11px]">
          {log.map((e) => (
            <li key={e.id} className="flex flex-wrap items-center justify-between gap-2 px-3 py-1.5">
              <span><span className="font-semibold text-ink">{e.actor}</span> {e.action} <span className="font-semibold">{e.side.toLowerCase()}</span>{e.fileName ? ` · ${e.fileName}` : ''}{e.action === 'replaced' && e.previousFileName ? ` (was ${e.previousFileName})` : ''}{e.action === 'removed' && e.previousFileName ? ` · ${e.previousFileName}` : ''}</span>
              <span className="text-slate-body">{fmt(e.at)}</span>
            </li>
          ))}
        </ul>
      )}

      {/* viewer */}
      {mobile && <p className="mt-1 text-[11px] text-slate-body">Tap a side to take a photo with your camera or choose one from your library. Tap a photo to view, replace or remove it.</p>}
      <Dialog open={!!open} onOpenChange={(o) => !o && setOpen(null)}>
        <DialogContent className="sm:max-w-2xl">
          <DialogHeader>
            <DialogTitle>{unitLabel} — {open}</DialogTitle>
            <DialogDescription>
              {current ? `${current.fileName}${current.sizeBytes ? ` · ${(current.sizeBytes / 1024 / 1024).toFixed(1)} MB` : ''} · uploaded by ${current.uploadedBy} · ${fmt(current.uploadedAt)}` : 'No photo in this slot.'}
            </DialogDescription>
          </DialogHeader>
          {current?.url && (
            // eslint-disable-next-line @next/next/no-img-element
            <img src={current.url} alt={`${unitLabel} ${open}`} className="max-h-[70vh] w-full rounded-lg object-contain bg-neutral-100" />
          )}
          <DialogFooter className="gap-2">
            <label className="cursor-pointer rounded-lg border border-line bg-white px-3 py-1.5 text-xs font-bold text-ink hover:bg-paper">
              {busy === open ? 'Uploading…' : mobile ? 'Retake / replace' : 'Replace photo'}
              <input type="file" accept={ACCEPT} className="hidden" onChange={(e) => { if (open) void put(open, e.target.files?.[0]); e.target.value = '' }} />
            </label>
            <button onClick={() => open && remove(open)} disabled={busy === open} className="rounded-lg border border-red-200 bg-red-50 px-3 py-1.5 text-xs font-bold text-danger hover:bg-red-100 disabled:opacity-50">Remove photo</button>
            <button onClick={() => setOpen(null)} className="rounded-lg bg-navy-900 px-3 py-1.5 text-xs font-bold text-white hover:bg-navy-800">Close</button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  )
}
