import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useTranslation } from '@/hooks/use-translation';
import { ChevronLeft, ChevronRight } from 'lucide-react';
import { FilterLabel } from './filter-label';
import { PERIODE_MAX_MOIS, decalerCle, decalerPeriode, estCleMois, libellePeriode, normaliserSaisiePeriode } from './format';

interface Props {
    /** YYYY-MM — premier mois. Valeur BRUTE du champ : elle peut être une frappe inachevée. */
    du: string;
    /** YYYY-MM — dernier mois, `''` pour un mois seul (« tout le mois »). */
    au: string;
    /**
     * Reçoit la période déjà normalisée (permutée, plafonnée) dès qu'elle est
     * complète. `inachevee` : un des champs natifs a un segment effacé — sa
     * valeur vaut `''` sans être vide (voir `periodeASoumettre()`).
     */
    onChange: (du: string, au: string, inachevee?: boolean) => void;
}

/**
 * « Du [mois] au [mois] » — ou un seul mois, et c'est alors le mois entier.
 *
 * ═════════════════════════════════════════════════════════════════════════════
 * POURQUOI UN SECOND CHAMP, ET PAS UN SÉLECTEUR DE DATES
 * ═════════════════════════════════════════════════════════════════════════════
 * La demande : « sélectionner plusieurs mois, depuis a jusqu'à b, sinon un seul
 * mois sélectionné suffit pour dire que c'est tout le mois ». Le grain est le
 * MOIS, parce que c'est celui de la déclaration : le `DateRangePicker` du reste
 * de l'application choisit des JOURS, et un 14 mars n'a aucun sens ici. Aucun
 * composant du dépôt ne choisit une plage de mois ; le champ natif existant est
 * donc doublé, et « Au » reste FACULTATIF — vide, il ne change rien à l'écran
 * d'avant.
 *
 * Les flèches encadrent la période entière et la font glisser de SA longueur
 * (un trimestre avance d'un trimestre). Leur libellé le dit, et leur infobulle
 * nomme la période d'arrivée — un pas de trois mois qu'on n'a pas vu venir
 * ressemblerait à un saut.
 *
 * La période reçue est normalisée comme le serveur la normalise
 * (`normaliserSaisiePeriode`) : les champs montrent toujours ce qui est
 * affiché, jamais une plage à l'envers que le serveur aurait remise dans
 * l'ordre sans le dire.
 */
export function PeriodeSelector({ du, au, onChange }: Props) {
    const { t } = useTranslation();
    const estPlage = au !== '';

    /*
     * `badInput` : le champ natif a un segment effacé (« mm/aaaa » à moitié
     * retapé). Sa valeur est alors `''`, comme un champ vidé — mais un « Au »
     * vidé veut dire « tout le mois », pas un « Au » qu'on est en train de
     * retaper. Sans ce drapeau, l'écran basculait sur un mois seul au milieu
     * de la frappe. La valeur brute reste dans l'état (le champ est contrôlé :
     * y écrire autre chose effacerait les segments déjà tapés).
     */
    const changer = (nouveauDu: string, nouvelAu: string, champ: HTMLInputElement) => {
        const periode = normaliserSaisiePeriode(nouveauDu, nouvelAu);
        onChange(periode.du, periode.au, champ.validity.badInput);
    };

    const precedente = decalerPeriode(du, au, -1);
    const suivante = decalerPeriode(du, au, 1);

    const libelleFleche = (sens: 'prev' | 'next') =>
        estPlage
            ? t('retenue', `period_${sens}_range`, sens === 'prev' ? 'Période précédente' : 'Période suivante')
            : t('retenue', `period_${sens}`, sens === 'prev' ? 'Mois précédent' : 'Mois suivant');

    return (
        <div className="flex flex-col gap-3 sm:flex-row sm:items-end">
            <div className="flex flex-col gap-1">
                <Label className="text-xs" htmlFor="retenue-periode-du">
                    {t('retenue', 'period_from', 'Du')}
                </Label>
                {/* Les flèches encadrent le sélecteur natif plutôt que de le
                    remplacer : un rattrapage se fait mois par mois, et
                    `<input type="month">` n'offre aucun pas-à-pas — il fallait
                    ouvrir le calendrier du navigateur pour reculer d'un mois. */}
                <div className="flex items-center gap-1">
                    <Button
                        variant="outline"
                        size="icon"
                        className="h-9 w-9 shrink-0"
                        onClick={() => onChange(precedente.du, precedente.au)}
                        aria-label={libelleFleche('prev')}
                        title={`${libelleFleche('prev')} — ${libellePeriode(precedente.du, precedente.au)}`}
                    >
                        <ChevronLeft className="h-4 w-4" />
                    </Button>
                    <Input
                        id="retenue-periode-du"
                        type="month"
                        value={du}
                        onChange={(e) => changer(e.target.value, au, e.target)}
                        className="h-9 w-[160px] tabular-nums"
                    />
                </div>
            </div>

            <div className="flex flex-col gap-1">
                <FilterLabel
                    active={estPlage}
                    onClear={() => onChange(du, '')}
                    titre={t('retenue', 'period_to_clear', 'Revenir au seul premier mois')}
                >
                    <span>
                        {t('retenue', 'period_to', 'Au')}
                        {/* Dit AVANT qu'on se pose la question : un champ vide
                            n'est pas un oubli, c'est le mois seul. */}
                        {!estPlage && (
                            <span className="text-muted-foreground font-normal"> · {t('retenue', 'period_to_optional', 'facultatif')}</span>
                        )}
                    </span>
                </FilterLabel>
                <div className="flex items-center gap-1">
                    {/* `min` / `max` guident le calendrier natif là où il existe ;
                        ce ne sont que des indications — la normalisation, elle,
                        s'applique partout, y compris au champ texte des
                        navigateurs qui ignorent `type="month"`. */}
                    <Input
                        type="month"
                        value={au}
                        min={estCleMois(du) ? du : undefined}
                        max={estCleMois(du) ? decalerCle(du, PERIODE_MAX_MOIS - 1) : undefined}
                        onChange={(e) => changer(du, e.target.value, e.target)}
                        aria-label={t('retenue', 'period_to', 'Au')}
                        title={t('retenue', 'period_to_hint', 'Vide : le mois de début, en entier. Douze mois au plus.')}
                        className="h-9 w-[160px] tabular-nums"
                    />
                    <Button
                        variant="outline"
                        size="icon"
                        className="h-9 w-9 shrink-0"
                        onClick={() => onChange(suivante.du, suivante.au)}
                        aria-label={libelleFleche('next')}
                        title={`${libelleFleche('next')} — ${libellePeriode(suivante.du, suivante.au)}`}
                    >
                        <ChevronRight className="h-4 w-4" />
                    </Button>
                </div>
            </div>
        </div>
    );
}
