import { Head, Link } from '@inertiajs/react';
import {
    AlertTriangle,
    CheckCircle2,
    Download,
    FileSearch,
    LoaderCircle,
    PenTool,
    Ruler,
    ScanLine,
    UploadCloud,
} from 'lucide-react';
import { useCallback, useMemo, useRef, useState } from 'react';
import type { ChangeEvent, DragEvent } from 'react';
import {
    MasterplanViewer,
    STATUS_ORDER,
    STATUS_STYLE,
} from '@/components/plan/masterplan-viewer';
import AppLayout from '@/layouts/app-layout';
import type {
    Masterplan,
    MasterplanLot,
    MasterplanPoint,
    PlanInspection,
} from '@/types/masterplan';
import type { LotStatus } from '@/types/portal';

interface MasterplanPageProps {
    development: {
        id: number;
        name: string;
        slug: string;
        location: string;
        sourceName: string | null;
        sourcePage: number | null;
    } | null;
    masterplan: Masterplan | null;
    projectsUrl: string;
}

type Phase = 'idle' | 'inspecting' | 'ready' | 'digitizing' | 'done';

const csrfToken = (): string =>
    document.querySelector<HTMLMetaElement>('meta[name="csrf-token"]')
        ?.content ?? '';

const colorName = (rgb: string): string => {
    const [red, green, blue] = rgb.split(',').map(Number);
    const table: Array<[string, [number, number, number]]> = [
        ['magenta', [255, 0, 255]],
        ['rosa', [255, 0, 63]],
        ['rojo', [255, 0, 0]],
        ['cian', [0, 255, 255]],
        ['azul', [0, 0, 255]],
        ['verde', [0, 255, 0]],
        ['negro', [0, 0, 0]],
        ['naranja', [255, 127, 0]],
    ];

    let best = rgb;
    let bestDistance = Number.POSITIVE_INFINITY;

    for (const [name, [r, g, b]] of table) {
        const distance = (red - r) ** 2 + (green - g) ** 2 + (blue - b) ** 2;

        if (distance < bestDistance) {
            bestDistance = distance;
            best = name;
        }
    }

    return best;
};

export default function MasterplanStudio({
    development,
    masterplan: initialMasterplan,
    projectsUrl,
}: MasterplanPageProps) {
    const [masterplan, setMasterplan] = useState<Masterplan | null>(
        initialMasterplan,
    );
    const [projectUrl, setProjectUrl] = useState<string | null>(null);
    const [phase, setPhase] = useState<Phase>(
        initialMasterplan ? 'done' : 'idle',
    );
    const [file, setFile] = useState<File | null>(null);
    const [inspection, setInspection] = useState<PlanInspection | null>(null);
    const [error, setError] = useState<string | null>(null);
    const [selectedId, setSelectedId] = useState<string | null>(null);
    const [dragOver, setDragOver] = useState(false);
    const [savingLot, setSavingLot] = useState(false);
    const [editing, setEditing] = useState<MasterplanLot['polygon'] | null>(
        null,
    );
    const inputRef = useRef<HTMLInputElement>(null);

    const lots = useMemo(() => masterplan?.lots ?? [], [masterplan]);
    const selectedLot = useMemo(
        () => lots.find((lot) => lot.id === selectedId) ?? null,
        [lots, selectedId],
    );

    const inspect = useCallback(async (picked: File) => {
        setFile(picked);
        setError(null);
        setInspection(null);
        setPhase('inspecting');

        const body = new FormData();
        body.append('file', picked);
        body.append('page', '1');

        try {
            const response = await fetch('/admin/digitalizador/analizar', {
                method: 'POST',
                headers: {
                    Accept: 'application/json',
                    'X-CSRF-TOKEN': csrfToken(),
                },
                body,
            });
            const payload = await response.json();

            if (!response.ok) {
                throw new Error(
                    payload.message ?? 'No fue posible analizar el plano.',
                );
            }

            setInspection(payload as PlanInspection);
            setPhase('ready');
        } catch (caught) {
            setError(
                caught instanceof Error
                    ? caught.message
                    : 'No fue posible analizar el plano.',
            );
            setPhase('idle');
        }
    }, []);

    const digitize = useCallback(async () => {
        if (!file) {
            return;
        }

        setError(null);
        setPhase('digitizing');

        const body = new FormData();
        body.append('file', file);
        body.append('page', String(inspection?.page ?? 1));
        body.append('source_name', file.name);

        if (development !== null) {
            body.append('development_id', String(development.id));
        }

        try {
            const response = await fetch('/admin/digitalizador/digitalizar', {
                method: 'POST',
                headers: {
                    Accept: 'application/json',
                    'X-CSRF-TOKEN': csrfToken(),
                },
                body,
            });
            const payload = await response.json();

            if (!response.ok) {
                throw new Error(
                    payload.message ?? 'No fue posible digitalizar el plano.',
                );
            }

            setMasterplan(payload as Masterplan);
            setProjectUrl(
                typeof payload.projectUrl === 'string'
                    ? payload.projectUrl
                    : null,
            );
            setSelectedId(null);
            setPhase('done');
        } catch (caught) {
            setError(
                caught instanceof Error
                    ? caught.message
                    : 'No fue posible digitalizar el plano.',
            );
            setPhase('ready');
        }
    }, [development, file, inspection?.page]);

    const updateLot = useCallback(
        async (lot: MasterplanLot, changes: Partial<MasterplanLot>) => {
            setMasterplan((current) =>
                current === null
                    ? current
                    : {
                          ...current,
                          lots: current.lots.map((item) =>
                              item.id === lot.id
                                  ? { ...item, ...changes }
                                  : item,
                          ),
                      },
            );

            if (lot.databaseId === undefined) {
                return;
            }

            setSavingLot(true);

            try {
                await fetch(`/admin/digitalizador/lote/${lot.databaseId}`, {
                    method: 'PATCH',
                    headers: {
                        Accept: 'application/json',
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': csrfToken(),
                    },
                    body: JSON.stringify(changes),
                });
            } finally {
                setSavingLot(false);
            }
        },
        [],
    );

    const exportJson = useCallback(() => {
        if (!masterplan) {
            return;
        }

        const blob = new Blob(
            [
                JSON.stringify(
                    {
                        project: development?.name ?? 'Plano digitalizado',
                        source: masterplan.source,
                        frame: masterplan.frame,
                        validation: masterplan.report,
                        lots: masterplan.lots,
                    },
                    null,
                    2,
                ),
            ],
            { type: 'application/json' },
        );
        const url = URL.createObjectURL(blob);
        const anchor = document.createElement('a');
        anchor.href = url;
        anchor.download = `${development?.slug ?? 'masterplan'}.json`;
        anchor.click();
        URL.revokeObjectURL(url);
    }, [development, masterplan]);

    const onDrop = useCallback(
        (event: DragEvent<HTMLDivElement>) => {
            event.preventDefault();
            setDragOver(false);
            const dropped = event.dataTransfer.files[0];

            if (dropped) {
                void inspect(dropped);
            }
        },
        [inspect],
    );

    const onPick = useCallback(
        (event: ChangeEvent<HTMLInputElement>) => {
            const picked = event.target.files?.[0];

            if (picked) {
                void inspect(picked);
            }
        },
        [inspect],
    );

    const report = masterplan?.report ?? null;

    return (
        <AppLayout
            breadcrumbs={[
                { title: 'Administración', href: '/admin' },
                { title: 'Digitalizador', href: '/admin/digitalizador' },
            ]}
        >
            <Head title="Digitalizador de planos · Masterplan dinámico" />

            <div className="flex h-[calc(100vh-4rem)] min-h-0 flex-col bg-[#f4f6f4]">
                <header className="flex flex-wrap items-center justify-between gap-3 border-b border-[#dfe5e2] bg-white px-4 py-3">
                    <div>
                        <h1 className="text-[17px] font-black tracking-tight text-[#17332b]">
                            {development?.name ?? 'Digitalizador de planos'}
                        </h1>
                        <p className="mt-0.5 text-[13px] text-[#6c7a72]">
                            Masterplan dinámico · lote, manzana, superficie y
                            medidas leídas del PDF
                        </p>
                        {report ? (
                            <span
                                className={`mt-1.5 inline-flex items-center gap-1.5 rounded-full px-2.5 py-1.5 text-[12px] font-bold ${
                                    report.complete
                                        ? 'bg-[#e9f6ef] text-[#237a53]'
                                        : 'bg-[#fdf0e4] text-[#9a5a1c]'
                                }`}
                            >
                                {report.complete ? (
                                    <CheckCircle2 className="size-3.5" />
                                ) : (
                                    <AlertTriangle className="size-3.5" />
                                )}
                                {report.rendered} de {report.labels_found} lotes
                                renderizados · {report.missing_count} pendientes
                            </span>
                        ) : null}
                    </div>

                    <div className="flex items-center gap-2">
                        {masterplan ? (
                            <button
                                type="button"
                                onClick={exportJson}
                                className="flex items-center gap-1.5 rounded-lg border border-[#d8e0da] bg-white px-3 py-2 text-[13px] font-semibold text-[#3c4a43] hover:bg-[#f2f6f3]"
                            >
                                <Download className="size-4" />
                                Exportar JSON
                            </button>
                        ) : null}
                        <button
                            type="button"
                            onClick={() => inputRef.current?.click()}
                            className="flex items-center gap-1.5 rounded-lg bg-[#17332b] px-3 py-2 text-[13px] font-semibold text-white hover:bg-[#1f473b]"
                        >
                            <UploadCloud className="size-4" />
                            {masterplan ? 'Cargar otro plano' : 'Cargar PDF'}
                        </button>
                        <Link
                            href={projectsUrl}
                            className="rounded-lg border border-[#d8e0da] bg-white px-3 py-2 text-[13px] font-semibold text-[#3c4a43] hover:bg-[#f2f6f3]"
                        >
                            Proyectos
                        </Link>
                    </div>
                </header>

                <input
                    ref={inputRef}
                    type="file"
                    accept="application/pdf"
                    className="hidden"
                    onChange={onPick}
                />

                <div className="grid min-h-0 flex-1 grid-cols-1 lg:grid-cols-[1fr_340px]">
                    <section className="relative min-h-0 border-r border-[#dfe5e2]">
                        {masterplan ? (
                            <MasterplanViewer
                                frame={masterplan.frame}
                                basePlanUrl={masterplan.basePlanUrl}
                                lots={lots}
                                selectedId={selectedId}
                                onSelect={(id) => {
                                    setEditing(null);
                                    setSelectedId(id);
                                }}
                                editing={editing}
                                onEditingChange={setEditing}
                            />
                        ) : (
                            <div
                                onDragOver={(event) => {
                                    event.preventDefault();
                                    setDragOver(true);
                                }}
                                onDragLeave={() => setDragOver(false)}
                                onDrop={onDrop}
                                className={`flex h-full items-center justify-center p-8 ${
                                    dragOver ? 'bg-[#eaf3ee]' : ''
                                }`}
                            >
                                <div className="max-w-md text-center">
                                    <div className="mx-auto flex size-14 items-center justify-center rounded-2xl bg-[#e9f0ea] text-[#315f4e]">
                                        <ScanLine className="size-6" />
                                    </div>
                                    <h2 className="mt-4 text-base font-bold text-[#17332b]">
                                        Sube el PDF del plano
                                    </h2>
                                    <p className="mt-2 text-xs leading-5 text-[#6c7a72]">
                                        Lotea lee las anotaciones AutoCAD SHX,
                                        los vectores y las líneas divisorias del
                                        propio PDF, valida que ningún lote quede
                                        sin polígono y genera el masterplan
                                        dinámico sobre el plano rasterizado.
                                    </p>
                                    <button
                                        type="button"
                                        onClick={() =>
                                            inputRef.current?.click()
                                        }
                                        className="mt-5 inline-flex items-center gap-2 rounded-xl bg-[#17332b] px-4 py-2.5 text-xs font-semibold text-white hover:bg-[#1f473b]"
                                    >
                                        <UploadCloud className="size-4.5" />
                                        Seleccionar PDF
                                    </button>
                                </div>
                            </div>
                        )}

                        {phase === 'inspecting' || phase === 'digitizing' ? (
                            <div className="absolute inset-0 z-20 flex items-center justify-center bg-[#eef2ef]/90 backdrop-blur-sm">
                                <div className="flex items-center gap-3 rounded-2xl border border-[#dfe5e2] bg-white px-5 py-4 shadow-lg">
                                    <LoaderCircle className="size-5 animate-spin text-[#315f4e]" />
                                    <div>
                                        <p className="text-xs font-bold text-[#17332b]">
                                            {phase === 'inspecting'
                                                ? 'Analizando el PDF'
                                                : 'Digitalizando el plano'}
                                        </p>
                                        <p className="mt-0.5 text-[12px] text-[#6c7a72]">
                                            {phase === 'inspecting'
                                                ? 'Leyendo anotaciones SHX, capas y vectores'
                                                : 'Reconstruyendo polígonos, validando cobertura y rasterizando'}
                                        </p>
                                    </div>
                                </div>
                            </div>
                        ) : null}
                    </section>

                    <aside className="min-h-0 overflow-y-auto bg-white p-4">
                        {error ? (
                            <p className="mb-4 rounded-xl border border-[#f0d3cb] bg-[#fdf1ee] px-3.5 py-3 text-[13px] text-[#8a3f32]">
                                {error}
                            </p>
                        ) : null}

                        {phase === 'ready' && inspection ? (
                            <InspectionPanel
                                inspection={inspection}
                                fileName={file?.name ?? 'plano.pdf'}
                                onDigitize={digitize}
                            />
                        ) : null}

                        {report ? <ReportPanel report={report} /> : null}

                        {masterplan ? (
                            <LotPanel
                                lot={selectedLot}
                                saving={savingLot}
                                editing={editing}
                                frame={masterplan.frame}
                                onChange={updateLot}
                                onStartEditing={setEditing}
                                onCancelEditing={() => setEditing(null)}
                            />
                        ) : null}

                        {masterplan && projectUrl ? (
                            <Link
                                href={projectUrl}
                                className="mt-5 block rounded-xl bg-[#17332b] px-3.5 py-3 text-center text-[13px] font-semibold text-white hover:bg-[#1f473b]"
                            >
                                Abrir el proyecto
                            </Link>
                        ) : null}
                    </aside>
                </div>
            </div>
        </AppLayout>
    );
}

function InspectionPanel({
    inspection,
    fileName,
    onDigitize,
}: {
    inspection: PlanInspection;
    fileName: string;
    onDigitize: () => void;
}) {
    const blocks =
        inspection.blocks.length > 1
            ? `${inspection.blocks[0]}–${inspection.blocks[inspection.blocks.length - 1]}`
            : (inspection.blocks[0] ?? 'No detectadas');

    return (
        <section className="mb-5 rounded-2xl border border-[#dfe5e2] p-4">
            <h2 className="flex items-center gap-2 text-[12px] font-black tracking-[0.08em] text-[#7c8b83] uppercase">
                <FileSearch className="size-4" />
                Configuración detectada
            </h2>
            <p className="mt-1.5 truncate text-[13px] font-semibold text-[#17332b]">
                {fileName}
            </p>

            <dl className="mt-3 space-y-1.5 text-[13px]">
                <Row
                    label="Tipo de PDF"
                    value={
                        inspection.type === 'vectorial'
                            ? 'Vectorial'
                            : 'Rasterizado'
                    }
                />
                <Row
                    label="AutoCAD SHX"
                    value={
                        inspection.shx_annotations > 0
                            ? `Detectado (${inspection.shx_annotations})`
                            : 'No detectado'
                    }
                />
                <Row
                    label="Etiquetas de lote"
                    value={String(inspection.lot_labels)}
                />
                <Row label="Manzanas" value={blocks} />
                <Row
                    label="Divisiones de lote"
                    value={
                        inspection.divider_colors.length > 0
                            ? inspection.divider_colors
                                  .map(colorName)
                                  .join(', ')
                            : 'Por topología'
                    }
                />
                <Row
                    label="Estados comerciales"
                    value={
                        inspection.statuses.length > 0
                            ? inspection.statuses.join(', ')
                            : 'Sin capas de estatus'
                    }
                />
                <Row
                    label="Superficies / medidas"
                    value={`${inspection.area_labels} / ${inspection.dimension_labels}`}
                />
                <Row
                    label="Segmentos vectoriales"
                    value={inspection.segments.toLocaleString('es-MX')}
                />
            </dl>

            <button
                type="button"
                onClick={onDigitize}
                disabled={inspection.lot_labels === 0}
                className="mt-4 flex w-full items-center justify-center gap-2 rounded-xl bg-[#17332b] px-3.5 py-3 text-[13px] font-bold text-white hover:bg-[#1f473b] disabled:cursor-not-allowed disabled:bg-[#9aa8a1]"
            >
                <PenTool className="size-4" />
                Digitalizar plano
            </button>
            {inspection.lot_labels === 0 ? (
                <p className="mt-2 text-[12px] leading-4 text-[#9a5a1c]">
                    No se encontraron etiquetas de lote legibles en el PDF. El
                    plano debe conservar su capa de texto o sus anotaciones
                    AutoCAD SHX.
                </p>
            ) : null}
        </section>
    );
}

function ReportPanel({
    report,
}: {
    report: NonNullable<Masterplan['report']>;
}) {
    const blocks = Object.entries(report.blocks);

    return (
        <section className="mb-5">
            <h2 className="text-[12px] font-black tracking-[0.08em] text-[#7c8b83] uppercase">
                Digitalización del plano
            </h2>

            <div className="mt-2 grid grid-cols-2 gap-2">
                <Stat
                    value={`${report.rendered} / ${report.labels_found}`}
                    label="LOTES RENDERIZADOS"
                    wide
                />
                {STATUS_ORDER.filter(
                    (status) =>
                        (report.statuses[spanishStatus(status)] ?? 0) > 0,
                ).map((status) => (
                    <Stat
                        key={status}
                        value={String(
                            report.statuses[spanishStatus(status)] ?? 0,
                        )}
                        label={STATUS_STYLE[status].label.toUpperCase()}
                    />
                ))}
            </div>

            <div
                className={`mt-3 rounded-xl border px-3.5 py-3 text-[12px] leading-4 ${
                    report.complete
                        ? 'border-[#cfe8d9] bg-[#f5faf7] text-[#326a4f]'
                        : 'border-[#f0dcc4] bg-[#fdf7ef] text-[#8a5a1c]'
                }`}
            >
                {report.complete ? (
                    <>
                        Cobertura {report.coverage}% · el PDF declara{' '}
                        {report.labels_found} etiquetas L-* y el masterplan
                        contiene {report.rendered} polígonos. Digitalización
                        completa.
                    </>
                ) : (
                    <>
                        Digitalización incompleta: {report.rendered} /{' '}
                        {report.labels_found} lotes. {report.missing_count}{' '}
                        pendientes
                        {report.missing.length > 0
                            ? `: ${report.missing.slice(0, 8).join(', ')}`
                            : '.'}
                    </>
                )}
            </div>

            <dl className="mt-3 space-y-1.5 text-[13px]">
                <Row
                    label="Con número"
                    value={`${report.with_number} / ${report.labels_found}`}
                />
                <Row
                    label="Con manzana"
                    value={`${report.with_block} / ${report.labels_found}`}
                />
                <Row
                    label="Con superficie"
                    value={`${report.with_area} / ${report.labels_found}`}
                />
                <Row
                    label="Con medidas"
                    value={`${report.with_dimensions} / ${report.labels_found}`}
                />
            </dl>

            {blocks.length > 0 ? (
                <>
                    <h3 className="mt-4 text-[12px] font-black tracking-[0.08em] text-[#7c8b83] uppercase">
                        Control por manzana
                    </h3>
                    <ul className="mt-2 grid grid-cols-2 gap-1.5">
                        {blocks.map(([code, block]) => (
                            <li
                                key={code}
                                className={`flex items-center justify-between rounded-lg border px-2.5 py-2 text-[12px] font-semibold ${
                                    block.rendered === block.expected
                                        ? 'border-[#dfe9e2] text-[#3c4a43]'
                                        : 'border-[#f0dcc4] bg-[#fdf7ef] text-[#8a5a1c]'
                                }`}
                            >
                                <span>MZ-{code}</span>
                                <span>
                                    {block.rendered} / {block.expected}
                                </span>
                            </li>
                        ))}
                    </ul>
                </>
            ) : null}
        </section>
    );
}

function LotPanel({
    lot,
    saving,
    editing,
    frame,
    onChange,
    onStartEditing,
    onCancelEditing,
}: {
    lot: MasterplanLot | null;
    saving: boolean;
    editing: MasterplanPoint[] | null;
    frame: Masterplan['frame'];
    onChange: (
        lot: MasterplanLot,
        changes: Partial<MasterplanLot>,
    ) => void | Promise<void>;
    onStartEditing: (points: MasterplanPoint[]) => void;
    onCancelEditing: () => void;
}) {
    if (!lot) {
        return (
            <section className="rounded-2xl border border-dashed border-[#cdd8d1] px-3 py-5 text-center">
                <p className="text-[13px] font-semibold text-[#3c4a43]">
                    Selecciona un lote
                </p>
                <p className="mt-1.5 text-[12px] leading-4 text-[#7c8b83]">
                    Aquí aparecerán su número, manzana, superficie y medidas
                    leídas del plano.
                </p>
            </section>
        );
    }

    const style = STATUS_STYLE[lot.status];
    const missing = lot.polygon.length < 3;

    /** A lot with no polygon starts from a small square on its own label. */
    const seed = (): MasterplanPoint[] => {
        if (lot.polygon.length >= 3) {
            return lot.polygon;
        }

        const [x, y] = lot.labelPoint ?? [frame.width / 2, frame.height / 2];
        const size = Math.max(20, frame.width * 0.012);

        return [
            [x - size, y - size],
            [x + size, y - size],
            [x + size, y + size],
            [x - size, y + size],
        ];
    };

    return (
        <section className="rounded-2xl border border-[#dfe5e2] p-4">
            <div className="flex items-center gap-2">
                <span
                    className="size-2.5 rounded-full border border-black/20"
                    style={{ backgroundColor: style.fill }}
                />
                <h2 className="text-sm font-black text-[#17332b]">
                    {lot.lot} · {lot.blockLabel ?? 'sin manzana'}
                </h2>
            </div>

            {missing && editing === null ? (
                <p className="mt-2.5 rounded-xl border border-[#f0dcc4] bg-[#fdf7ef] px-3 py-2.5 text-[12px] leading-4 text-[#8a5a1c]">
                    Este lote no obtuvo polígono del plano. Dibújalo a mano para
                    completarlo.
                </p>
            ) : null}

            <div className="mt-3 grid grid-cols-2 gap-2">
                <Field label="Lote" value={lot.lot} />
                <Field label="Manzana" value={lot.blockLabel ?? '—'} />
                <Field
                    label="Superficie"
                    value={
                        lot.area === null ? '—' : `${lot.area.toFixed(2)} m²`
                    }
                />
                <Field label="Estatus" value={style.label} />
                <Field
                    label="Medidas indicadas en plano"
                    value={
                        lot.dimensions.length > 0
                            ? lot.dimensions.join(' × ')
                            : '—'
                    }
                    wide
                />
            </div>

            {editing === null ? (
                <button
                    type="button"
                    onClick={() => onStartEditing(seed())}
                    className="mt-3 flex w-full items-center justify-center gap-2 rounded-xl border border-[#d8e0da] px-3 py-2.5 text-[12px] font-bold text-[#3c4a43] hover:bg-[#f2f6f3]"
                >
                    <PenTool className="size-3.5" />
                    {missing ? 'Dibujar el lote' : 'Corregir geometría'}
                </button>
            ) : (
                <div className="mt-3 rounded-xl border border-[#f0dcc4] bg-[#fdf7ef] p-3">
                    <p className="text-[12px] leading-4 text-[#8a5a1c]">
                        Arrastra los vértices sobre el plano. La superficie se
                        recalcula a la escala del plano al guardar.
                    </p>
                    <div className="mt-2.5 flex gap-2">
                        <button
                            type="button"
                            onClick={onCancelEditing}
                            className="flex-1 rounded-lg border border-[#d8e0da] bg-white px-3 py-2 text-[12px] font-bold text-[#3c4a43] hover:bg-[#f2f6f3]"
                        >
                            Cancelar
                        </button>
                        <button
                            type="button"
                            onClick={() => {
                                void onChange(lot, { polygon: editing });
                                onCancelEditing();
                            }}
                            className="flex-1 rounded-lg bg-[#17332b] px-3 py-2 text-[12px] font-bold text-white hover:bg-[#1f473b]"
                        >
                            Guardar geometría
                        </button>
                    </div>
                </div>
            )}

            <label className="mt-3 block">
                <span className="text-[11px] font-bold tracking-wide text-[#7c8b83] uppercase">
                    Cambiar estatus comercial
                </span>
                <select
                    value={lot.status}
                    onChange={(event) =>
                        void onChange(lot, {
                            status: event.target.value as LotStatus,
                        })
                    }
                    className="mt-1.5 w-full rounded-lg border border-[#d8e0da] bg-white px-3 py-2.5 text-[13px] outline-none focus:border-[#315f4e]"
                >
                    {STATUS_ORDER.map((status) => (
                        <option key={status} value={status}>
                            {STATUS_STYLE[status].label}
                        </option>
                    ))}
                </select>
            </label>

            <label className="mt-3 block">
                <span className="text-[11px] font-bold tracking-wide text-[#7c8b83] uppercase">
                    Nota
                </span>
                <textarea
                    defaultValue={lot.note}
                    onBlur={(event) =>
                        event.target.value !== lot.note
                            ? void onChange(lot, { note: event.target.value })
                            : undefined
                    }
                    placeholder="Cliente, precio, observaciones…"
                    className="mt-1.5 min-h-20 w-full resize-y rounded-lg border border-[#d8e0da] bg-white px-3 py-2.5 text-[13px] outline-none focus:border-[#315f4e]"
                />
            </label>

            <p className="mt-2 flex items-center gap-1.5 text-[12px] text-[#7c8b83]">
                <Ruler className="size-3.5" />
                {lot.statusEvidence ?? 'Sin evidencia registrada.'}
            </p>
            <p className="mt-1 text-[12px] text-[#9aa8a1]">
                Confianza {lot.confidence ?? 0}% · pasada {lot.pass ?? '—'}
                {saving ? ' · guardando…' : ''}
            </p>
        </section>
    );
}

function Row({ label, value }: { label: string; value: string }) {
    return (
        <div className="flex items-baseline justify-between gap-3">
            <dt className="text-[#7c8b83]">{label}</dt>
            <dd className="text-right font-semibold text-[#17332b]">{value}</dd>
        </div>
    );
}

function Stat({
    value,
    label,
    wide,
}: {
    value: string;
    label: string;
    wide?: boolean;
}) {
    return (
        <div
            className={`rounded-xl border border-[#e2e9e4] px-3 py-2 ${wide ? 'col-span-2' : ''}`}
        >
            <strong className="block text-lg leading-tight font-black text-[#17332b]">
                {value}
            </strong>
            <span className="text-[11px] font-semibold tracking-wide text-[#7c8b83]">
                {label}
            </span>
        </div>
    );
}

function Field({
    label,
    value,
    wide,
}: {
    label: string;
    value: string;
    wide?: boolean;
}) {
    return (
        <div
            className={`rounded-lg border border-[#e2e9e4] px-3.5 py-3 ${wide ? 'col-span-2' : ''}`}
        >
            <span className="text-[11px] font-bold tracking-wide text-[#7c8b83] uppercase">
                {label}
            </span>
            <b className="mt-0.5 block text-[14px] font-bold text-[#17332b]">
                {value}
            </b>
        </div>
    );
}

const spanishStatus = (status: LotStatus): string =>
    ({
        sold: 'vendido',
        held: 'apartado',
        available: 'disponible',
        blocked: 'bloqueado',
    })[status];
