import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { useTranslation } from '@/hooks/use-translation';
import { Lock, Plus, Trash2 } from 'lucide-react';
import { Fragment } from 'react';
import {
    addThreshold,
    isFloorThreshold,
    newWindow,
    nextThreshold,
    OBA_WINDOW_MAX_DAY,
    obaRuleIssues,
    occFromField,
    occToField,
    patchThreshold,
    removeThreshold,
    sortThresholds,
    type ObaIssue,
} from '../../lib/oba-rules';
import { equivalentLabel, multiplierEquivalent, RULE_BOUNDS } from '../../lib/rule-units';
import type { ObaRule, ObaThreshold } from '../../types';
import ObaWindowCard from './ObaWindowCard';

const NS = 'yield.index';

interface ObaEditorProps {
    value: ObaRule[];
    onChange: (rules: ObaRule[]) => void;
    /** Named starting points (conservative/recommended/aggressive) used to seed the matrix. */
    presets: Record<string, ObaRule[]>;
}

/**
 * Table OBA (ajustement par remplissage) entièrement éditable. Un preset ne
 * fait qu'AMORCER les valeurs — chaque échéance et chaque seuil se modifient
 * ensuite : « rempli à ≥ X % → prix × multiplicateur », par échéance.
 * Composant contrôlé (value + onChange), partagé par l'éditeur d'un logement
 * et par la feuille d'un groupe de règles.
 *
 * Le remplissage ne fait que MONTER les prix (décision produit ; le serveur le
 * vérifie aussi) :
 *  - la première ligne de chaque échéance est « Dès 0 % », verrouillée : son
 *    taux ne se modifie pas et elle ne se supprime pas (son multiplicateur,
 *    lui, reste réglable, ×1 au moins) ;
 *  - une échéance ajoutée part de [0 % → ×1], à la suite de la dernière et
 *    jamais au-delà du jour 365 ; un seuil ajouté se place 10 points
 *    au-dessus du dernier, au multiplicateur de son voisin du dessous ;
 *  - le champ multiplicateur refuse (indice HTML) moins de ×1, et un
 *    avertissement dit, avant l'enregistrement, ce que le serveur refusera.
 *
 * Toute la logique vit dans lib/oba-rules.ts, testée : le TRI s'applique à la
 * VALEUR, jamais au seul affichage — modification et suppression passent par
 * l'index de la ligne. Il a lieu à l'ajout, à la suppression, et quand le
 * focus QUITTE la carte de l'échéance (ObaWindowCard) : jamais pendant qu'un
 * champ ou un bouton de la carte est en main. Trier en quittant le champ
 * « taux » déplaçait la ligne entre ce blur et le geste suivant (Tab vers son
 * multiplicateur, clic sur sa corbeille), qui touchait alors un autre seuil.
 * Tant que le focus reste dans la carte, les lignes ne bougent pas : la clé
 * d'index des lignes reste donc juste.
 */
export default function ObaEditor({ value, onChange, presets }: ObaEditorProps) {
    const { t, locale } = useTranslation();
    const soit = t(NS, 'unit_equivalent', 'soit :value');
    const rules = Array.isArray(value) ? value : [];

    // Appels t() LITTÉRAUX : YieldTranslationsTest ne voit que ceux-là.
    const issueText: Record<ObaIssue, string> = {
        floor_missing: t(
            NS,
            'oba_issue_floor_missing',
            'Cette échéance doit commencer par une ligne « Dès 0 % » : sans elle, elle sera refusée à l’enregistrement.',
        ),
        below_floor: t(
            NS,
            'oba_issue_below_floor',
            'Un multiplicateur est sous ×1 : le remplissage ne fait que monter les prix, les baisses viennent de la règle dernière minute.',
        ),
        not_monotone: t(
            NS,
            'oba_issue_not_monotone',
            'Le multiplicateur baisse quand le remplissage monte : cette échéance sera refusée à l’enregistrement.',
        ),
        duplicate_occ: t(NS, 'oba_issue_duplicate_occ', 'Deux seuils portent le même taux : l’un des deux ne servirait jamais.'),
    };

    const lockedText = t(
        NS,
        'oba_floor_locked',
        'Première ligne de chaque échéance : toujours 0 %, elle ne se supprime pas. Son multiplicateur se règle, jamais sous ×1 : le prix n’est jamais baissé.',
    );

    const patchRule = (i: number, patch: Partial<ObaRule>) => onChange(rules.map((r, idx) => (idx === i ? { ...r, ...patch } : r)));
    const replaceRule = (i: number, rule: ObaRule) => onChange(rules.map((r, idx) => (idx === i ? rule : r)));
    const patchRow = (ri: number, ti: number, patch: Partial<ObaThreshold>) => replaceRule(ri, patchThreshold(rules[ri], ti, patch));
    const removeWindow = (ri: number) => onChange(rules.filter((_, idx) => idx !== ri));

    return (
        <div className="space-y-4">
            <div className="flex flex-wrap items-center justify-between gap-2">
                <p className="text-muted-foreground max-w-md text-xs leading-relaxed">
                    {t(
                        NS,
                        'oba_intro',
                        'Pour chaque échéance (nombre de jours avant la nuit), le prix monte quand le logement se remplit : le remplissage ne fait que monter les prix, les baisses viennent de la règle dernière minute. Le taux se lit sur les nuits vendables (séjours propriétaires, demandes non acceptées et blocages exclus). Charge un preset puis affine.',
                    )}
                </p>
                <div className="flex shrink-0 items-center gap-2">
                    <Label className="text-muted-foreground text-xs">{t(NS, 'oba_preset_label', 'Preset')}</Label>
                    <Select onValueChange={(p) => presets[p] && onChange(presets[p])}>
                        <SelectTrigger className="h-8 w-40">
                            <SelectValue placeholder={t(NS, 'oba_preset_placeholder', 'Choisir…')} />
                        </SelectTrigger>
                        <SelectContent>
                            <SelectItem value="conservative">{t(NS, 'oba_conservative', 'Conservateur')}</SelectItem>
                            <SelectItem value="recommended">{t(NS, 'oba_recommended', 'Recommandé')}</SelectItem>
                            <SelectItem value="aggressive">{t(NS, 'oba_aggressive', 'Agressif')}</SelectItem>
                        </SelectContent>
                    </Select>
                </div>
            </div>

            {rules.map((rule, ri) => {
                const issues = obaRuleIssues(rule);
                return (
                    <ObaWindowCard
                        key={ri}
                        className="overflow-hidden rounded-lg border"
                        // Tri de la VALEUR quand le focus quitte l'échéance — jamais à chaque frappe, ni entre deux gestes dans la carte.
                        onFocusLeave={() => {
                            const sorted = sortThresholds(rules[ri]);
                            if (sorted !== rules[ri]) replaceRule(ri, sorted);
                        }}
                    >
                        {/* Window header — lead-time range */}
                        <div className="bg-muted/40 flex items-center justify-between gap-2 border-b px-3 py-2">
                            <div className="flex items-center gap-1.5 text-sm">
                                <span className="text-muted-foreground text-xs">{t(NS, 'oba_lead_time', 'Échéance : entre')}</span>
                                <Input
                                    type="number"
                                    min={0}
                                    max={OBA_WINDOW_MAX_DAY}
                                    value={rule.window[0]}
                                    onChange={(e) => patchRule(ri, { window: [Number(e.target.value), rule.window[1]] })}
                                    className="h-7 w-14 text-center text-xs"
                                />
                                <span className="text-muted-foreground text-xs">{t(NS, 'oba_and', 'et')}</span>
                                <Input
                                    type="number"
                                    min={0}
                                    max={OBA_WINDOW_MAX_DAY}
                                    value={rule.window[1]}
                                    onChange={(e) => patchRule(ri, { window: [rule.window[0], Number(e.target.value)] })}
                                    className="h-7 w-14 text-center text-xs"
                                />
                                <span className="text-muted-foreground text-xs">{t(NS, 'oba_days_before', 'jours avant')}</span>
                            </div>
                            <Button
                                type="button"
                                variant="ghost"
                                size="icon"
                                className="h-7 w-7"
                                onClick={() => removeWindow(ri)}
                                aria-label={t(NS, 'oba_remove_window', 'Supprimer la fenêtre')}
                            >
                                <Trash2 className="h-3.5 w-3.5 text-red-500" />
                            </Button>
                        </div>

                        {/* Thresholds table */}
                        <div className="p-3">
                            <div className="grid grid-cols-[1fr_1fr_2rem] items-center gap-x-3 gap-y-2">
                                <span className="text-muted-foreground text-[11px] font-medium">{t(NS, 'oba_col_occ', 'Si rempli à')}</span>
                                <span className="text-muted-foreground text-[11px] font-medium">{t(NS, 'oba_col_mult', 'Prix ×')}</span>
                                <span />

                                {rule.thresholds.map((th, ti) => {
                                    const floor = isFloorThreshold(rule, ti);
                                    return (
                                        <Fragment key={ti}>
                                            {floor ? (
                                                // Ligne « Dès 0 % » : le taux n'est pas un champ — il ne se modifie pas.
                                                <div className="flex h-8 items-center gap-1 text-sm" title={lockedText}>
                                                    <Lock className="text-muted-foreground h-3 w-3" aria-hidden />
                                                    <span>{t(NS, 'oba_floor_row', 'Dès 0 %')}</span>
                                                </div>
                                            ) : (
                                                <div className="flex items-center gap-1">
                                                    <span className="text-muted-foreground text-xs">≥</span>
                                                    <Input
                                                        type="number"
                                                        min={0}
                                                        max={100}
                                                        // Champ vidé = taux illisible (NaN), pas un second « 0 % ».
                                                        value={occToField(th.occ)}
                                                        onChange={(e) => patchRow(ri, ti, { occ: occFromField(e.target.value) })}
                                                        className="h-8 w-20 text-right"
                                                    />
                                                    <span className="text-muted-foreground text-xs">%</span>
                                                </div>
                                            )}
                                            <div className="flex flex-col gap-0.5">
                                                <div className="flex items-center gap-1">
                                                    <span className="text-muted-foreground text-xs">×</span>
                                                    <Input
                                                        type="number"
                                                        step="0.01"
                                                        min={RULE_BOUNDS.obaMult.min}
                                                        max={RULE_BOUNDS.obaMult.max}
                                                        value={th.mult}
                                                        onChange={(e) => patchRow(ri, ti, { mult: Number(e.target.value) })}
                                                        className="h-8 w-20 text-right"
                                                    />
                                                </div>
                                                {/* Le multiplicateur lu en % : « ×1,05 → soit +5 % », à côté d'une colonne d'occupation elle aussi en %. */}
                                                <span className="text-muted-foreground pl-3 text-[11px]">
                                                    {equivalentLabel(soit, multiplierEquivalent(th.mult, locale))}
                                                </span>
                                            </div>
                                            <Button
                                                type="button"
                                                variant="ghost"
                                                size="icon"
                                                className="h-8 w-8"
                                                disabled={floor}
                                                title={floor ? lockedText : undefined}
                                                onClick={() => replaceRule(ri, removeThreshold(rules[ri], ti))}
                                                aria-label={floor ? lockedText : t(NS, 'oba_remove_threshold', 'Supprimer le seuil')}
                                            >
                                                <Trash2 className={floor ? 'text-muted-foreground h-3.5 w-3.5' : 'h-3.5 w-3.5 text-red-400'} />
                                            </Button>
                                        </Fragment>
                                    );
                                })}
                            </div>

                            {issues.length > 0 && (
                                <ul className="mt-2 space-y-0.5 text-xs text-amber-700 dark:text-amber-300">
                                    {issues.map((issue) => (
                                        <li key={issue}>{issueText[issue]}</li>
                                    ))}
                                </ul>
                            )}

                            <Button
                                type="button"
                                variant="ghost"
                                size="sm"
                                className="mt-2 h-7 text-xs"
                                disabled={nextThreshold(rule) === null}
                                onClick={() => replaceRule(ri, addThreshold(rule))}
                            >
                                <Plus className="h-3.5 w-3.5" />
                                {t(NS, 'oba_add_threshold', 'Ajouter un seuil')}
                            </Button>
                        </div>
                    </ObaWindowCard>
                );
            })}

            <Button
                type="button"
                variant="outline"
                size="sm"
                // Grisé quand la dernière échéance finit au jour 365 : plus de place.
                disabled={newWindow(rules) === null}
                onClick={() => {
                    const added = newWindow(rules);
                    if (added !== null) onChange([...rules, added]);
                }}
            >
                <Plus className="h-4 w-4" />
                {t(NS, 'oba_add_window', 'Ajouter une échéance')}
            </Button>
        </div>
    );
}
