"use client"

import { useEffect, useRef, useState } from "react"
import { toast } from "sonner"
import {
    AlertTriangle,
    Camera,
    ChevronLeft,
    ChevronRight,
    CheckCircle2,
    Image as ImageIcon,
    Loader2,
    Mic,
    StickyNote,
    Trash2,
    Video,
    X,
} from "lucide-react"

import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogFooter,
    DialogHeader,
    DialogTitle,
} from "@/shared/components/ui/dialog"
import { Alert, AlertDescription, AlertTitle } from "@/shared/components/ui/alert"
import { Badge } from "@/shared/components/ui/badge"
import { Button } from "@/shared/components/ui/button"
import { Textarea } from "@/shared/components/ui/textarea"
import { Label } from "@/shared/components/ui/label"
import { useAuthApi } from "@/shared/useApi"
import { CheckpointMediaLightbox, type LightboxItem } from "@/modules/inspections/checkpoint-media-lightbox"

export type Severity = "good" | "attention" | "critical" | "na" | "not_inspected"
export type RecordType = "capture_photo" | "record_video" | "record_audio" | "record_conditions" | "wire_frame" | "none"

export type CheckpointMedia = {
    id: number
    url: string | null
    media_type: "photo" | "video" | "audio" | "document"
    sort_order: number
    caption?: string | null
}

export type Checkpoint = {
    id: number
    name: string
    description?: string | null
    severity?: Severity | null
    status?: string | null
    technician_notes?: string | null
    section_name?: string | null
    record_type?: RecordType | null
    condition_rate?: number | null
    media?: CheckpointMedia[]
    attachments?: CheckpointMedia[]
}

const SEVERITY: { value: Severity; label: string; cls: string }[] = [
    { value: "good", label: "Good", cls: "bg-emerald-100 text-emerald-800 hover:bg-emerald-200 border-emerald-200" },
    { value: "attention", label: "Attention", cls: "bg-amber-100 text-amber-800 hover:bg-amber-200 border-amber-200" },
    { value: "critical", label: "Critical", cls: "bg-rose-100 text-rose-800 hover:bg-rose-200 border-rose-200" },
    { value: "na", label: "N/A", cls: "bg-slate-100 text-slate-700 hover:bg-slate-200 border-slate-200" },
]

/** A checkpoint is "complete" once severity is set AND the required recording (if any) is captured. */
export function isCheckpointComplete(cp: Checkpoint): boolean {
    const sev = (cp.severity as Severity) ?? "not_inspected"
    if (sev === "not_inspected") return false
    if (sev === "na") return true

    const rt = (cp.record_type as RecordType) ?? "none"
    const items = cp.attachments ?? cp.media ?? []
    if (rt === "capture_photo") return items.some((m) => m.media_type === "photo")
    if (rt === "record_video") return items.some((m) => m.media_type === "video")
    if (rt === "record_audio") return items.some((m) => m.media_type === "audio")
    if (rt === "record_conditions") return cp.condition_rate != null
    return true
}

type Props = {
    open: boolean
    onOpenChange: (o: boolean) => void
    /** Full ordered list of checkpoints (typically section-flattened from the page). */
    checkpoints: Checkpoint[]
    /** Index into `checkpoints`. null = dialog closed. */
    activeIndex: number | null
    onIndexChange: (i: number) => void
    onSaved: () => void
    /** Optimistic patch back to the parent so the row updates instantly. */
    onPatch?: (checkpointId: number, patch: Partial<Checkpoint>) => void
}

export function CheckpointFillDialog({
    open,
    onOpenChange,
    checkpoints,
    activeIndex,
    onIndexChange,
    onSaved,
    onPatch,
}: Props) {
    const api = useAuthApi()
    const photoInputRef = useRef<HTMLInputElement>(null)
    const videoInputRef = useRef<HTMLInputElement>(null)
    const audioInputRef = useRef<HTMLInputElement>(null)

    // Local state — seeded only when the active checkpoint changes
    // (not on every parent refetch, so unsaved notes don't get clobbered).
    const [severity, setSeverity] = useState<Severity>("not_inspected")
    const [notes, setNotes] = useState("")
    const [conditionRate, setConditionRate] = useState<number>(50)
    const [media, setMedia] = useState<CheckpointMedia[]>([])
    const [savingNote, setSavingNote] = useState(false)
    const [savingCondition, setSavingCondition] = useState(false)
    const [uploading, setUploading] = useState(false)
    const [lightbox, setLightbox] = useState<LightboxItem | null>(null)

    const checkpoint = activeIndex != null ? checkpoints[activeIndex] : null
    const checkpointId = checkpoint?.id ?? null

    // Reseed only when the *checkpoint identity* changes (open or step nav).
    useEffect(() => {
        if (checkpoint) {
            setSeverity((checkpoint.severity as Severity) ?? "not_inspected")
            setNotes(checkpoint.technician_notes ?? "")
            setConditionRate(checkpoint.condition_rate ?? 50)
            setMedia(checkpoint.attachments ?? checkpoint.media ?? [])
        }
        // Intentionally only depends on the id — not on the whole prop object.
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [checkpointId, open])

    if (!checkpoint) return null

    const recordType = (checkpoint.record_type as RecordType) ?? "none"
    const skipsMedia = severity === "na" || recordType === "none" || recordType === "wire_frame"
    const needsSeverity = severity === "not_inspected"
    const needsPhoto = !skipsMedia && recordType === "capture_photo" && !media.some((m) => m.media_type === "photo")
    const needsVideo = !skipsMedia && recordType === "record_video" && !media.some((m) => m.media_type === "video")
    const needsAudio = !skipsMedia && recordType === "record_audio" && !media.some((m) => m.media_type === "audio")
    const needsCondition = !skipsMedia && recordType === "record_conditions" && checkpoint.condition_rate == null
    const allDone = !needsSeverity && !needsPhoto && !needsVideo && !needsAudio && !needsCondition

    const hasUnsavedNote = notes !== (checkpoint.technician_notes ?? "")
    const isFirst = activeIndex === 0
    const isLast = activeIndex === checkpoints.length - 1

    // All field saves rely on the optimistic `onPatch` to keep the parent
    // page in sync. We intentionally do NOT call `onSaved()` here, because a
    // full inspection refetch on every chip click was causing the dialog tree
    // to re-render in a way that flickered the modal closed/open. `onSaved`
    // is reserved for the explicit page-level "load" callsite (initial mount
    // + nav). The server is authoritative — if anything ever diverges, the
    // user can reopen the dialog or refresh.

    const updateSeverity = async (s: Severity) => {
        setSeverity(s)
        onPatch?.(checkpoint.id, { severity: s })
        try {
            await api.inspections.updateCheckpoint(String(checkpoint.id), { severity: s } as any)
        } catch (e: any) {
            toast.error(e?.payload?.message ?? "Failed to save finding")
        }
    }

    const saveNotes = async () => {
        if (!hasUnsavedNote) return
        setSavingNote(true)
        try {
            await api.inspections.updateCheckpoint(String(checkpoint.id), { technician_notes: notes } as any)
            onPatch?.(checkpoint.id, { technician_notes: notes })
            toast.success("Note saved")
        } catch (e: any) {
            toast.error(e?.payload?.message ?? "Failed to save note")
        } finally {
            setSavingNote(false)
        }
    }

    const saveCondition = async (v: number) => {
        setConditionRate(v)
        onPatch?.(checkpoint.id, { condition_rate: v })
        setSavingCondition(true)
        try {
            await api.inspections.updateCheckpoint(String(checkpoint.id), { condition_rate: v } as any)
        } catch (e: any) {
            toast.error(e?.payload?.message ?? "Failed to save condition")
        } finally {
            setSavingCondition(false)
        }
    }

    const handleFiles = async (filesList: FileList | null) => {
        if (!filesList || filesList.length === 0) return
        const files = Array.from(filesList).slice(0, 10)
        setUploading(true)
        try {
            const res = await api.inspections.uploadCheckpointAttachments(checkpoint.id, files)
            const added = (res.data as any[]) ?? []
            const nextMedia = [...media, ...added]
            setMedia(nextMedia)
            onPatch?.(checkpoint.id, { attachments: nextMedia, media: nextMedia } as any)
            toast.success("Saved")
        } catch (e: any) {
            toast.error(e?.payload?.message ?? "Upload failed")
        } finally {
            setUploading(false)
            if (photoInputRef.current) photoInputRef.current.value = ""
            if (videoInputRef.current) videoInputRef.current.value = ""
            if (audioInputRef.current) audioInputRef.current.value = ""
        }
    }

    const deleteAttachment = async (mediaId: number) => {
        try {
            await api.inspections.destroyCheckpointAttachment(checkpoint.id, mediaId)
            const nextMedia = media.filter((x) => x.id !== mediaId)
            setMedia(nextMedia)
            onPatch?.(checkpoint.id, { attachments: nextMedia, media: nextMedia } as any)
        } catch (e: any) {
            toast.error(e?.payload?.message ?? "Failed to remove")
        }
    }

    const goNext = async () => {
        // Belt-and-suspenders — the button is also `disabled={!allDone}`.
        if (!allDone) return
        if (hasUnsavedNote) await saveNotes()
        if (isLast) {
            onOpenChange(false)
        } else if (activeIndex != null) {
            onIndexChange(activeIndex + 1)
        }
    }

    const goPrev = async () => {
        if (hasUnsavedNote) await saveNotes()
        if (activeIndex != null && activeIndex > 0) onIndexChange(activeIndex - 1)
    }

    return (
        <>
            <Dialog open={open} onOpenChange={onOpenChange}>
                <DialogContent className="sm:max-w-xl max-h-[90vh] overflow-y-auto">
                    <DialogHeader>
                        <div className="flex items-center justify-between gap-2">
                            <div className="min-w-0">
                                <DialogTitle className="flex items-center gap-2">
                                    <span className="truncate">{checkpoint.name}</span>
                                    {allDone && <CheckCircle2 className="size-4 text-emerald-600 shrink-0" />}
                                </DialogTitle>
                                {checkpoint.section_name && (
                                    <DialogDescription>
                                        {checkpoint.section_name} · {(activeIndex ?? 0) + 1} of {checkpoints.length}
                                    </DialogDescription>
                                )}
                            </div>
                        </div>
                    </DialogHeader>

                    {!allDone && (
                        <Alert variant="default" className="border-amber-200 bg-amber-50/60">
                            <AlertTriangle className="text-amber-700" />
                            <AlertTitle className="text-amber-900">Still required</AlertTitle>
                            <AlertDescription className="text-amber-900/90">
                                <ul className="list-disc list-inside space-y-0.5">
                                    {needsSeverity && <li>Pick a finding</li>}
                                    {needsPhoto && <li>Add at least one photo</li>}
                                    {needsVideo && <li>Add at least one video</li>}
                                    {needsAudio && <li>Add at least one audio recording</li>}
                                    {needsCondition && <li>Set the condition rating</li>}
                                </ul>
                            </AlertDescription>
                        </Alert>
                    )}

                    <div className="space-y-5">
                        {/* Finding */}
                        <div>
                            <div className="mb-2 flex items-center justify-between">
                                <Label className="flex items-center gap-2">
                                    Finding <Badge variant="secondary" className="text-[10px]">required</Badge>
                                </Label>
                                {!needsSeverity && <CheckCircle2 className="size-4 text-emerald-600" />}
                            </div>
                            <div className="flex flex-wrap gap-2">
                                {SEVERITY.map((opt) => (
                                    <button
                                        key={opt.value}
                                        type="button"
                                        onClick={() => updateSeverity(opt.value)}
                                        className={`rounded-full px-4 py-1.5 text-sm font-medium border transition ${opt.cls} ${
                                            severity === opt.value ? "ring-2 ring-offset-1 ring-foreground/30" : "opacity-70 hover:opacity-100"
                                        }`}
                                    >
                                        {opt.label}
                                    </button>
                                ))}
                            </div>
                        </div>

                        {/* Condition rating */}
                        {recordType === "record_conditions" && severity !== "na" && (
                            <div>
                                <div className="mb-2 flex items-center justify-between">
                                    <Label className="flex items-center gap-2">
                                        Condition rating <Badge variant="secondary" className="text-[10px]">required</Badge>
                                    </Label>
                                    {!needsCondition && <CheckCircle2 className="size-4 text-emerald-600" />}
                                </div>
                                <div className="flex items-center gap-3">
                                    <input
                                        type="range"
                                        min={0}
                                        max={100}
                                        step={5}
                                        value={conditionRate}
                                        onChange={(e) => setConditionRate(Number(e.target.value))}
                                        onMouseUp={(e) => saveCondition(Number((e.target as HTMLInputElement).value))}
                                        onTouchEnd={(e) => saveCondition(Number((e.target as HTMLInputElement).value))}
                                        className="flex-1 accent-foreground"
                                        disabled={savingCondition}
                                    />
                                    <span className="w-12 text-right text-sm tabular-nums font-medium">{conditionRate}%</span>
                                </div>
                                <p className="text-xs text-muted-foreground mt-1">0 = worn / broken · 100 = like new.</p>
                            </div>
                        )}

                        {/* Media — only the relevant kind for this record_type */}
                        {!skipsMedia && (
                            <MediaSection
                                recordType={recordType}
                                media={media}
                                uploading={uploading}
                                required={needsPhoto || needsVideo || needsAudio}
                                satisfied={
                                    (recordType === "capture_photo" && !needsPhoto) ||
                                    (recordType === "record_video" && !needsVideo) ||
                                    (recordType === "record_audio" && !needsAudio)
                                }
                                onPick={(kind) => {
                                    if (kind === "photo") photoInputRef.current?.click()
                                    else if (kind === "video") videoInputRef.current?.click()
                                    else audioInputRef.current?.click()
                                }}
                                onDelete={deleteAttachment}
                                onPreview={(item) => setLightbox(item)}
                            />
                        )}

                        <input ref={photoInputRef} type="file" accept="image/*" capture="environment" multiple onChange={(e) => handleFiles(e.target.files)} className="hidden" />
                        <input ref={videoInputRef} type="file" accept="video/*" capture="environment" multiple onChange={(e) => handleFiles(e.target.files)} className="hidden" />
                        <input ref={audioInputRef} type="file" accept="audio/*" capture multiple onChange={(e) => handleFiles(e.target.files)} className="hidden" />

                        {/* Notes */}
                        <div>
                            <div className="mb-2 flex items-center justify-between">
                                <Label htmlFor="cp-notes" className="flex items-center gap-2">
                                    <StickyNote className="size-3.5" /> Technician notes
                                    <Badge variant="outline" className="text-[10px]">optional</Badge>
                                </Label>
                                {hasUnsavedNote && (
                                    <span className="text-[11px] text-amber-700">Unsaved</span>
                                )}
                            </div>
                            <Textarea
                                id="cp-notes"
                                value={notes}
                                onChange={(e) => setNotes(e.target.value)}
                                rows={3}
                                placeholder="e.g. Pads at 3mm, suggest replacement before next service"
                            />
                            <div className="mt-2 flex justify-end">
                                <Button
                                    type="button"
                                    size="sm"
                                    variant={hasUnsavedNote ? "default" : "outline"}
                                    onClick={saveNotes}
                                    disabled={savingNote || !hasUnsavedNote}
                                >
                                    {savingNote ? "Saving…" : "Update note"}
                                </Button>
                            </div>
                        </div>
                    </div>

                    <DialogFooter className="!justify-between items-center gap-2 flex-wrap">
                        <Button variant="ghost" size="sm" onClick={() => onOpenChange(false)}>
                            <X className="size-4" /> Close
                        </Button>
                        <div className="flex flex-col items-end gap-1">
                            <div className="flex items-center gap-2">
                                <Button variant="outline" size="sm" onClick={goPrev} disabled={isFirst}>
                                    <ChevronLeft className="size-4" /> Previous
                                </Button>
                                <Button
                                    size="sm"
                                    onClick={goNext}
                                    disabled={!allDone}
                                    title={!allDone ? "Complete the required fields to continue" : undefined}
                                >
                                    {isLast ? "Done" : (hasUnsavedNote ? "Save & next" : "Next")}
                                    {!isLast && <ChevronRight className="size-4" />}
                                </Button>
                            </div>
                            {!allDone && (
                                <span className="text-[11px] text-muted-foreground">
                                    Complete the required fields to continue.
                                </span>
                            )}
                        </div>
                    </DialogFooter>
                </DialogContent>
            </Dialog>

            <CheckpointMediaLightbox
                open={!!lightbox}
                onOpenChange={(o) => { if (!o) setLightbox(null) }}
                item={lightbox}
            />
        </>
    )
}

function MediaSection({
    recordType,
    media,
    uploading,
    required,
    satisfied,
    onPick,
    onDelete,
    onPreview,
}: {
    recordType: RecordType
    media: CheckpointMedia[]
    uploading: boolean
    required: boolean
    satisfied: boolean
    onPick: (kind: "photo" | "video" | "audio") => void
    onDelete: (id: number) => void
    onPreview: (item: LightboxItem) => void
}) {
    let label = "Recording"
    let icon = <Camera className="size-3.5" />
    let cta = "Take / pick file"
    let kind: "photo" | "video" | "audio" = "photo"

    if (recordType === "capture_photo") { label = "Photo"; cta = "Take or pick photo"; icon = <Camera className="size-3.5" />; kind = "photo" }
    if (recordType === "record_video") { label = "Video"; cta = "Record or pick video"; icon = <Video className="size-3.5" />; kind = "video" }
    if (recordType === "record_audio") { label = "Audio"; cta = "Record or pick audio"; icon = <Mic className="size-3.5" />; kind = "audio" }

    const matching = media.filter((m) => {
        if (recordType === "capture_photo") return m.media_type === "photo"
        if (recordType === "record_video") return m.media_type === "video"
        if (recordType === "record_audio") return m.media_type === "audio"
        return true
    })

    return (
        <div>
            <div className="mb-2 flex items-center justify-between">
                <Label className="flex items-center gap-2">
                    {label}
                    {required && <Badge variant="secondary" className="text-[10px]">required</Badge>}
                    {satisfied && <CheckCircle2 className="size-4 text-emerald-600" />}
                </Label>
                <Button type="button" size="sm" variant="outline" onClick={() => onPick(kind)} disabled={uploading}>
                    {uploading ? <Loader2 className="size-3.5 animate-spin" /> : icon}
                    {uploading ? "Uploading…" : cta}
                </Button>
            </div>
            {matching.length === 0 ? (
                <div className="rounded-md border border-dashed bg-muted/40 p-6 text-center text-xs text-muted-foreground flex flex-col items-center gap-1.5">
                    <ImageIcon className="size-5" />
                    {required ? `Tap the button above to add a ${label.toLowerCase()}` : `No ${label.toLowerCase()} yet`}
                </div>
            ) : (
                <div className={kind === "audio" ? "space-y-2" : "grid grid-cols-3 sm:grid-cols-4 gap-2"}>
                    {matching.map((m) => (
                        <div key={m.id} className="relative group rounded-md overflow-hidden border bg-muted">
                            <button
                                type="button"
                                onClick={() => onPreview(m as LightboxItem)}
                                className="block w-full"
                            >
                                {m.media_type === "photo" && m.url && (
                                    // eslint-disable-next-line @next/next/no-img-element
                                    <img src={m.url} alt={m.caption ?? ""} className="block w-full aspect-square object-cover" />
                                )}
                                {m.media_type === "video" && m.url && (
                                    <div className="relative w-full aspect-square">
                                        <video src={m.url} className="block w-full h-full object-cover" />
                                        <div className="absolute inset-0 flex items-center justify-center bg-black/30 text-white">
                                            <Video className="size-6" />
                                        </div>
                                    </div>
                                )}
                                {m.media_type === "audio" && m.url && (
                                    <div className="p-2 w-full">
                                        <audio src={m.url} controls className="w-full" />
                                    </div>
                                )}
                            </button>
                            <Badge variant="secondary" className="absolute top-1 left-1 text-[9px] capitalize">{m.media_type}</Badge>
                            <button
                                type="button"
                                onClick={() => onDelete(m.id)}
                                className="absolute top-1 right-1 rounded-full bg-foreground/80 text-background p-1 opacity-0 group-hover:opacity-100 transition"
                                aria-label="Remove"
                            >
                                <Trash2 className="size-3" />
                            </button>
                        </div>
                    ))}
                </div>
            )}
        </div>
    )
}
