import { useEffect, useRef, useState } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
import type { KeyRow, KeyRowTarget, LocaleStats } from '@/api/types';
import { SourceText } from '@/components/SourceText';
import { STATUS_META, StatusDot } from '@/components/Status';
import { TranslationInput } from '@/editor/TranslationInput';

interface Props {
    rows: KeyRow[];
    total: number;
    loading: boolean;
    /** Langues cibles du projet, avec l'habilitation d'écriture de l'utilisateur. */
    locales: LocaleStats[];
    sourceCode: string;
    selectedId: string | null;
    onSelect: (id: string) => void;
}

/**
 * La vue par clé : une clé, toutes ses langues.
 *
 * Elle ne remplace pas la grille par langue, elle répond à une autre question.
 * La grille sert la traductrice qui vide sa file dans UNE langue ; celle-ci
 * sert qui doit juger d'une clé — « ce libellé est-il prêt partout ? » — avant
 * une mise en production, ou juste après avoir ajouté une clé.
 *
 * **Les langues sont repliées par défaut.** Sept champs de saisie ouverts par
 * clé produiraient un mur illisible et une page de vingt mille pixels ; la
 * bande de statuts donne la réponse d'un coup d'œil, et l'on ouvre la seule
 * langue sur laquelle on veut agir. C'est aussi ce qui garde la virtualisation
 * honnête : les hauteurs restent proches de l'estimation.
 */
export function KeyGrid({
    rows,
    total,
    loading,
    locales,
    sourceCode,
    selectedId,
    onSelect,
}: Props) {
    const parentRef = useRef<HTMLDivElement>(null);

    // Même règle que dans la grille par langue : un panneau de contexte vide au
    // moment où l'utilisateur découvre l'écran est une colonne perdue.
    const first = rows[0]?.id;
    useEffect(() => {
        if (selectedId === null && first !== undefined) onSelect(first);
    }, [first, selectedId, onSelect]);

    const virtualizer = useVirtualizer({
        count: rows.length,
        getScrollElement: () => parentRef.current,
        estimateSize: () => 120,
        overscan: 6,
        getItemKey: (index) => rows[index]?.id ?? index,
    });

    if (loading && rows.length === 0) {
        return (
            <div className="flex flex-1 items-center justify-center text-sm text-ink-400">
                Chargement des clés…
            </div>
        );
    }

    if (rows.length === 0) {
        return (
            <div className="flex flex-1 flex-col items-center justify-center gap-1 px-6 text-center">
                <p className="text-sm font-medium text-ink-700">Aucune clé ne correspond.</p>
                <p className="text-xs text-ink-400">
                    En vue par clé, le filtre de statut retient les clés dont{' '}
                    <strong>au moins une</strong> langue est dans cet état.
                </p>
            </div>
        );
    }

    return (
        <div className="flex min-w-0 flex-1 flex-col">
            <div className="flex shrink-0 items-baseline justify-between border-b border-ink-200 bg-white px-4 py-1.5">
                <span className="tabular text-xs text-ink-500">
                    {rows.length < total ? `${rows.length} sur ${total}` : `${total}`} clé
                    {total > 1 ? 's' : ''}
                </span>
                <span className="text-[11px] text-ink-400">
                    {locales.length} langue{locales.length > 1 ? 's' : ''} cible
                    {locales.length > 1 ? 's' : ''}
                </span>
            </div>

            <div ref={parentRef} className="min-h-0 flex-1 overflow-y-auto">
                <div className="relative w-full" style={{ height: virtualizer.getTotalSize() }}>
                    {virtualizer.getVirtualItems().map((item) => {
                        const row = rows[item.index];
                        if (!row) return null;

                        return (
                            <div
                                key={item.key}
                                ref={virtualizer.measureElement}
                                data-index={item.index}
                                className="absolute left-0 top-0 w-full"
                                style={{ transform: `translateY(${item.start}px)` }}
                            >
                                <KeyCard
                                    row={row}
                                    locales={locales}
                                    sourceCode={sourceCode}
                                    selected={row.id === selectedId}
                                    onSelect={() => onSelect(row.id)}
                                />
                            </div>
                        );
                    })}
                </div>
            </div>
        </div>
    );
}

function KeyCard({
    row,
    locales,
    sourceCode,
    selected,
    onSelect,
}: {
    row: KeyRow;
    locales: LocaleStats[];
    sourceCode: string;
    selected: boolean;
    onSelect: () => void;
}) {
    const [openLocale, setOpenLocale] = useState<string | null>(null);

    const byCode = new Map(row.targets.map((target) => [target.locale, target]));

    return (
        <div
            onClick={onSelect}
            className={`border-b border-ink-100 px-4 py-3 transition-colors ${
                selected ? 'bg-accent-soft/30' : 'bg-white'
            }`}
        >
            <div className="flex items-center gap-2">
                <span className="truncate font-mono text-xs text-ink-700">{row.keyPath}</span>

                <span className="ml-auto flex shrink-0 items-center gap-1">
                    {row.platforms.map((slug) => (
                        <span
                            key={slug}
                            className="rounded bg-ink-100 px-1 py-0.5 font-mono text-[10px] text-ink-500"
                        >
                            {slug}
                        </span>
                    ))}
                    {row.platforms.length === 0 && (
                        <span
                            className="rounded bg-amber-100 px-1 py-0.5 text-[10px] text-amber-800"
                            title="Rattachée à aucune plateforme : n'entre dans aucun fichier livré."
                        >
                            non assignée
                        </span>
                    )}
                    <span
                        className={`tabular ml-1 rounded px-1.5 py-0.5 text-[11px] font-medium ${
                            row.completion === 100
                                ? 'bg-emerald-100 text-emerald-800'
                                : 'bg-ink-100 text-ink-600'
                        }`}
                        title="Part des langues cibles dans un état publiable."
                    >
                        {row.completion}%
                    </span>
                </span>
            </div>

            <p className="mt-1.5 flex gap-2 text-sm leading-snug">
                <span className="mt-0.5 shrink-0 font-mono text-[11px] text-ink-400">
                    {sourceCode}
                </span>
                <span className="whitespace-pre-wrap text-ink-600">
                    {row.sourceValue === null ? (
                        <em className="text-ink-300">source absente</em>
                    ) : (
                        <SourceText value={row.sourceValue} />
                    )}
                </span>
            </p>

            {/* La bande de langues : une ligne par langue, refermée. Elle répond
                à « où en est cette clé ? » sans rien ouvrir. */}
            <div className="mt-2 divide-y divide-ink-50 rounded border border-ink-100">
                {locales.map((locale) => {
                    const target = byCode.get(locale.code);
                    const open = openLocale === locale.code;

                    return (
                        <LocaleLine
                            key={locale.code}
                            keyUuid={row.id}
                            locale={locale}
                            target={target}
                            maxLength={row.maxLength}
                            open={open}
                            onToggle={() => setOpenLocale(open ? null : locale.code)}
                        />
                    );
                })}
            </div>
        </div>
    );
}

function LocaleLine({
    keyUuid,
    locale,
    target,
    maxLength,
    open,
    onToggle,
}: {
    keyUuid: string;
    locale: LocaleStats;
    target: KeyRowTarget | undefined;
    maxLength: number | null;
    open: boolean;
    onToggle: () => void;
}) {
    const status = target?.status ?? 'untranslated';
    const value = target?.value ?? null;
    const meta = STATUS_META[status];

    return (
        <div className={open ? 'bg-ink-50' : ''}>
            <button
                type="button"
                onClick={onToggle}
                className="flex w-full items-center gap-2 px-2 py-1 text-left transition-colors hover:bg-ink-50"
            >
                <span className="w-12 shrink-0 font-mono text-[11px] text-ink-500">
                    {locale.code}
                </span>

                <StatusDot status={status} />

                <span
                    className={`min-w-0 flex-1 truncate text-sm ${
                        value === null ? 'text-ink-300' : 'text-ink-800'
                    }`}
                    dir={locale.direction}
                >
                    {value ?? meta.label}
                </span>

                {target?.isStale === true && (
                    <span className="shrink-0 rounded bg-red-50 px-1.5 py-0.5 text-[10px] font-medium text-red-700">
                        source modifiée
                    </span>
                )}

                {/* Dit AVANT d'ouvrir le champ. Découvrir qu'on n'a pas le droit
                    d'écrire après avoir tapé sa traduction est le pire moment. */}
                {!locale.canWrite && (
                    <span className="shrink-0 text-[10px] text-ink-400">consultation</span>
                )}

                <span className="shrink-0 text-[10px] text-ink-300">{open ? '▾' : '▸'}</span>
            </button>

            {open && (
                <div className="px-2 pb-2 pl-16">
                    {locale.canWrite ? (
                        <TranslationInput
                            keyUuid={keyUuid}
                            locale={locale.code}
                            value={value}
                            version={target?.version ?? 0}
                            direction={locale.direction}
                            pluralCategories={locale.pluralCategories}
                            maxLength={maxLength}
                            autoFocus
                            dense
                        />
                    ) : (
                        <p className="rounded border border-dashed border-ink-200 px-2 py-1 text-sm text-ink-400">
                            {value ?? '—'}
                        </p>
                    )}

                    {target?.updatedBy != null && (
                        <p className="mt-1 text-[11px] text-ink-400">
                            {target.updatedBy}
                            {target.updatedAt !== null &&
                                ` · ${new Date(target.updatedAt).toLocaleDateString('fr-FR')}`}
                            {target.isMachineTranslated && ' · traduction automatique'}
                        </p>
                    )}
                </div>
            )}
        </div>
    );
}
