import { useState } from 'react';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
    Card,
    CardContent,
    CardDescription,
    CardFooter,
    CardHeader,
    CardTitle,
} from '@/components/ui/card';
import {
    Select,
    SelectContent,
    SelectGroup,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from '@/components/ui/select';
import { Skeleton } from '@/components/ui/skeleton';
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
import type {
    EstadoConservacionElemento,
    PatologiaCodigo,
    PatologiaFilaData,
    PatologiasData,
    Severidad,
    SistemaConstructivo,
} from '@/generated/types';
import { index as elementosIndex } from '@/routes/ficha/elementos';
import { useCatalogo } from '../../hooks/use-catalogo';
import {
    ESTADO_CONSERVACION_ELEMENTO_LABELS,
    PATOLOGIA_CODIGO_LABELS,
    SEVERIDAD_LABELS,
    SISTEMA_CONSTRUCTIVO_LABELS,
} from '../../lib/enum-labels';
import { useSectionForm } from '../../lib/section-form-context';
import type { SeccionProps } from '..';

type ElementoSeleccionado = {
    elemento_id: number;
    nombre: string;
    categoria: string | null;
    sort_order: number;
    sist_const: SistemaConstructivo | null;
    mat_acabados: string | null;
    estado_conservacion: EstadoConservacionElemento | null;
};

type DraftPatologia = {
    codigo: PatologiaCodigo | null;
    severidad: Severidad;
};

const PATOLOGIA_OPTIONS = Object.entries(PATOLOGIA_CODIGO_LABELS) as Array<[
    PatologiaCodigo,
    string,
]>;

const SEVERIDAD_OPTIONS = Object.entries(SEVERIDAD_LABELS) as Array<[
    Severidad,
    string,
]>;

const DEFAULT_DRAFT: DraftPatologia = {
    codigo: null,
    severidad: 'm',
};

export function Patologias({ fichaId }: SeccionProps) {
    const { data, setData } = useSectionForm<PatologiasData>();
    const {
        data: elementos,
        loading,
        error,
    } = useCatalogo<ElementoSeleccionado[]>(
        elementosIndex.url({ ficha: fichaId }),
    );
    const [drafts, setDrafts] = useState<Record<number, DraftPatologia>>({});

    const items = elementos ?? [];

    function filaFor(elementoId: number): PatologiaFilaData | undefined {
        return data.filas.find((fila) => fila.elemento_id === elementoId);
    }

    function draftFor(elementoId: number): DraftPatologia {
        return drafts[elementoId] ?? DEFAULT_DRAFT;
    }

    function updateDraft(
        elementoId: number,
        patch: Partial<DraftPatologia>,
    ): void {
        setDrafts((current) => ({
            ...current,
            [elementoId]: {
                ...draftFor(elementoId),
                ...patch,
            },
        }));
    }

    function setFilas(filas: PatologiaFilaData[]): void {
        setData('filas', filas);
    }

    function addPatologia(elementoId: number): void {
        const draft = draftFor(elementoId);
        if (!draft.codigo) {
            return;
        }

        const existing = filaFor(elementoId);
        const patologias = existing?.patologias ?? [];

        if (patologias.some((item) => item.codigo === draft.codigo)) {
            return;
        }

        const nextFila: PatologiaFilaData = {
            elemento_id: elementoId,
            patologias: [
                ...patologias,
                {
                    codigo: draft.codigo,
                    severidad: draft.severidad,
                },
            ],
        };

        setFilas(
            existing
                ? data.filas.map((fila) =>
                      fila.elemento_id === elementoId ? nextFila : fila,
                  )
                : [...data.filas, nextFila],
        );

        setDrafts((current) => ({
            ...current,
            [elementoId]: DEFAULT_DRAFT,
        }));
    }

    function removePatologia(
        elementoId: number,
        codigo: PatologiaCodigo,
    ): void {
        const next = data.filas
            .map((fila) => {
                if (fila.elemento_id !== elementoId) {
                    return fila;
                }

                return {
                    ...fila,
                    patologias: fila.patologias.filter(
                        (item) => item.codigo !== codigo,
                    ),
                };
            })
            .filter((fila) => fila.patologias.length > 0);

        setFilas(next);
    }

    if (loading && !elementos) {
        return <PatologiasSkeleton />;
    }

    if (error) {
        return (
            <Alert variant="destructive">
                <AlertTitle>No se pudieron cargar los elementos</AlertTitle>
                <AlertDescription>{error}</AlertDescription>
            </Alert>
        );
    }

    if (items.length === 0) {
        return (
            <Alert>
                <AlertTitle>Sin elementos tecnológicos</AlertTitle>
                <AlertDescription>
                    Esta sección depende de los elementos registrados en la
                    sección 16.1. Complete primero Elementos Tecnológicos.
                </AlertDescription>
            </Alert>
        );
    }

    return (
        <div className="flex flex-col gap-4">
            <Alert>
                <AlertTitle>Elementos desde la sección 16.1</AlertTitle>
                <AlertDescription>
                    Registre patologías únicamente sobre los elementos
                    tecnológicos ya seleccionados.
                </AlertDescription>
            </Alert>

            <div className="flex flex-col gap-4">
                {items.map((elemento) => {
                    const fila = filaFor(elemento.elemento_id);
                    const patologias = fila?.patologias ?? [];
                    const draft = draftFor(elemento.elemento_id);

                    return (
                        <Card key={elemento.elemento_id}>
                            <CardHeader>
                                <CardTitle className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
                                    <span>{elemento.nombre}</span>
                                    {elemento.categoria && (
                                        <Badge variant="outline">
                                            {elemento.categoria}
                                        </Badge>
                                    )}
                                </CardTitle>
                                <CardDescription className="flex flex-wrap gap-2 pt-1">
                                    <ElementoBadge
                                        label="Sistema"
                                        value={
                                            elemento.sist_const
                                                ? SISTEMA_CONSTRUCTIVO_LABELS[
                                                      elemento.sist_const
                                                  ]
                                                : null
                                        }
                                    />
                                    <ElementoBadge
                                        label="Estado"
                                        value={
                                            elemento.estado_conservacion
                                                ? ESTADO_CONSERVACION_ELEMENTO_LABELS[
                                                      elemento
                                                          .estado_conservacion
                                                  ]
                                                : null
                                        }
                                    />
                                    <ElementoBadge
                                        label="Material"
                                        value={elemento.mat_acabados}
                                    />
                                </CardDescription>
                            </CardHeader>

                            <CardContent>
                                {patologias.length > 0 ? (
                                    <div className="flex flex-wrap gap-2">
                                        {patologias.map((patologia) => (
                                            <Badge
                                                key={patologia.codigo}
                                                variant="secondary"
                                                className="gap-2"
                                            >
                                                <span>
                                                    {
                                                        PATOLOGIA_CODIGO_LABELS[
                                                            patologia.codigo
                                                        ]
                                                    }{' '}
                                                    ·{' '}
                                                    {
                                                        SEVERIDAD_LABELS[
                                                            patologia.severidad
                                                        ]
                                                    }
                                                </span>
                                                <Button
                                                    type="button"
                                                    variant="ghost"
                                                    size="icon-xs"
                                                    className="text-muted-foreground hover:text-foreground"
                                                    onClick={() =>
                                                        removePatologia(
                                                            elemento.elemento_id,
                                                            patologia.codigo,
                                                        )
                                                    }
                                                    aria-label={`Quitar ${PATOLOGIA_CODIGO_LABELS[patologia.codigo]}`}
                                                >
                                                    x
                                                </Button>
                                            </Badge>
                                        ))}
                                    </div>
                                ) : (
                                    <p className="text-sm text-muted-foreground">
                                        Sin patologías registradas.
                                    </p>
                                )}
                            </CardContent>

                            <CardFooter className="flex flex-col items-stretch gap-2 sm:flex-row sm:items-center">
                                <Select
                                    value={draft.codigo ?? undefined}
                                    onValueChange={(value) =>
                                        updateDraft(elemento.elemento_id, {
                                            codigo: value as PatologiaCodigo,
                                        })
                                    }
                                >
                                    <SelectTrigger className="w-full sm:w-72" size="sm">
                                        <SelectValue placeholder="Seleccionar patología" />
                                    </SelectTrigger>
                                    <SelectContent>
                                        <SelectGroup>
                                            {PATOLOGIA_OPTIONS.map(
                                                ([codigo, label]) => (
                                                    <SelectItem
                                                        key={codigo}
                                                        value={codigo}
                                                        disabled={patologias.some(
                                                            (item) =>
                                                                item.codigo ===
                                                                codigo,
                                                        )}
                                                    >
                                                        {label}
                                                    </SelectItem>
                                                ),
                                            )}
                                        </SelectGroup>
                                    </SelectContent>
                                </Select>

                                <ToggleGroup
                                    type="single"
                                    value={draft.severidad}
                                    onValueChange={(value) => {
                                        if (value) {
                                            updateDraft(elemento.elemento_id, {
                                                severidad: value as Severidad,
                                            });
                                        }
                                    }}
                                    variant="outline"
                                    size="sm"
                                >
                                    {SEVERIDAD_OPTIONS.map(([value, label]) => (
                                        <ToggleGroupItem
                                            key={value}
                                            value={value}
                                            aria-label={label}
                                        >
                                            {label[0]}
                                        </ToggleGroupItem>
                                    ))}
                                </ToggleGroup>

                                <Button
                                    type="button"
                                    size="sm"
                                    onClick={() =>
                                        addPatologia(elemento.elemento_id)
                                    }
                                    disabled={!draft.codigo}
                                >
                                    Agregar
                                </Button>
                            </CardFooter>
                        </Card>
                    );
                })}
            </div>
        </div>
    );
}

function ElementoBadge({
    label,
    value,
}: {
    label: string;
    value: string | null;
}) {
    if (!value) {
        return null;
    }

    return (
        <Badge variant="outline">
            {label}: {value}
        </Badge>
    );
}

function PatologiasSkeleton() {
    return (
        <div className="flex flex-col gap-4">
            <Skeleton className="h-16 w-full" />
            <Skeleton className="h-44 w-full" />
            <Skeleton className="h-44 w-full" />
        </div>
    );
}
