import { Button } from '@/components/ui/button';
import { useTranslation } from '@/hooks/use-translation';
import { PlusIcon } from 'lucide-react';
import { useMemo, useState } from 'react';
import SeasonTemplateGallery, {
    INTENSITY_BAR_CLASS,
    TIMELINE_BASE_PRICE_CLASS,
    TIMELINE_MANUAL_CLASS,
} from '../../../logements/components/season-template-gallery';
import SeasonTimeline, { type TimelineSegment } from '../../../logements/components/season-timeline';
import { addOneYear, toLocalISODate, type SeasonIntensity, type SeasonTemplate } from '../../../logements/season-range-utils';
import {
    flattenSeasonSegments,
    isCompleteSeason,
    templateChipResolver,
    templateEvent,
    withoutBackgroundOverlapping,
} from '../../lib/season-calendar';
import type { MovableHolidays, YieldSeason, YieldSeasonality } from '../../types';
import YieldSeasonRow from '../YieldSeasonRow';

const NS = 'yield.index';

/** Table vide partagée : un `{}` par défaut, recréé à chaque rendu, invaliderait les mémos ci-dessous. */
const NO_HOLIDAYS: MovableHolidays = {};

/** Default percent adjustment when a template chip is added, keyed by intensity. */
const INTENSITY_DEFAULT_PCT: Record<SeasonIntensity, number> = {
    low: -15,
    mid: 0,
    high: 20,
    peak: 40,
    event: 30,
};

interface SeasonsEditorProps {
    value: YieldSeasonality;
    onChange: (value: YieldSeasonality) => void;
    seasonTemplates?: SeasonTemplate[];
    /** Dates des fêtes mobiles (config/yield-holidays.php) : sans elles, un Aïd ne tombe sur aucune nuit. */
    holidays?: MovableHolidays;
}

/**
 * Controlled date-range seasonality editor: template gallery, editable season
 * rows, the base-% for uncovered dates, and a live coverage timeline. Extracted
 * from YieldRuleEditor so the per-house editor and the rule-group editor share
 * the exact same UI.
 *
 * La frise, la galerie et les lignes raisonnent sur les OCCURRENCES des
 * saisons (lib/season-calendar.ts, copie du moteur des prix), jamais sur leurs
 * dates brutes : une saison « Chaque année » garde les dates de sa première
 * occurrence, un Aïd n'a que des dates de cache. La frise est découpée jour
 * par jour selon la saison qui l'emporte (événement, puis saison de fond,
 * puis socle) : ses segments sont disjoints même quand un événement est posé
 * dans une saison.
 */
export default function SeasonsEditor({ value, onChange, seasonTemplates = [], holidays = NO_HOLIDAYS }: SeasonsEditorProps) {
    const { t } = useTranslation();
    // Index of the season row whose % input should grab focus (template chip add).
    const [focusPctIndex, setFocusPctIndex] = useState<number | null>(null);

    const today = useMemo(() => toLocalISODate(new Date()), []);
    const horizon = useMemo(() => addOneYear(today), [today]);

    const seasons = value.seasons;
    const setSeasons = (next: YieldSeason[]) => onChange({ ...value, seasons: next });

    const handleAddSeason = () => {
        setFocusPctIndex(seasons.length);
        setSeasons([...seasons, { name: '', start_date: '', end_date: '', pct: 0 }]);
    };

    /**
     * Template chip click, default pct from the intensity:
     *  - gabarit à fête (Aïd Adha, Aïd Fitr) : l'ÉVÉNEMENT à date mobile, tel
     *    que le défaut le pose (templateEvent) — jamais une saison à dates
     *    fixes. Rien n'est retiré : un événement a le droit d'être dans une
     *    saison de fond, et la galerie grise la puce quand la fête est déjà là
     *    ou qu'un autre événement occupe ses nuits ;
     *  - sinon : a one-off background season on the projected dates. Toute
     *    saison de FOND complète dont une occurrence recouvre la plage est
     *    retirée (en pratique aucune : la galerie grise une telle puce) ; les
     *    événements et les lignes en cours de saisie restent.
     */
    const handlePickTemplate = (picked: { name: string; start_date: string; end_date: string }, tpl: SeasonTemplate | undefined) => {
        const pct = INTENSITY_DEFAULT_PCT[tpl?.intensity ?? 'mid'];
        const event = tpl ? templateEvent(tpl, pct, today, holidays) : null;
        if (event !== null) {
            setFocusPctIndex(seasons.length);
            setSeasons([...seasons, event]);
            return;
        }

        const kept = withoutBackgroundOverlapping(seasons, picked, holidays);
        setFocusPctIndex(kept.length);
        setSeasons([...kept, { ...picked, pct }]);
    };

    const handleSeasonChange = (index: number, patch: Partial<YieldSeason>) => {
        setFocusPctIndex(null);
        setSeasons(seasons.map((s, i) => (i === index ? { ...s, ...patch } : s)));
    };

    const removeSeason = (index: number) => {
        setFocusPctIndex(null);
        setSeasons(seasons.filter((_, i) => i !== index));
    };

    const templateByName = useMemo(() => new Map(seasonTemplates.map((tpl) => [tpl.name, tpl])), [seasonTemplates]);

    /** Signed percent for labels: "+45%" / "-15%" / "0%". */
    const fmtPct = (pct: number): string => `${pct > 0 ? '+' : ''}${pct}%`;

    /**
     * Seules les lignes COMPLÈTES comptent pour la frise et la galerie : une
     * ligne en cours de saisie (fin tapée, début encore vide) ne doit pas
     * colorer la frise — le serveur la refuserait.
     */
    const complete = useMemo(() => seasons.filter(isCompleteSeason), [seasons]);

    // Jour par jour sur un an : recalculé seulement quand les saisons changent.
    const segments = useMemo(() => flattenSeasonSegments(complete, today, horizon, holidays), [complete, today, horizon, holidays]);

    const timelineSegments: TimelineSegment[] = segments.map((segment) => {
        if (segment.season === null) {
            // Dates not covered by a season simply use the base price.
            return { ...segment, color: TIMELINE_BASE_PRICE_CLASS, label: t(NS, 'timeline_base_price', 'Prix de base') };
        }
        const tpl = segment.season.name ? templateByName.get(segment.season.name) : undefined;
        return {
            start_date: segment.start_date,
            end_date: segment.end_date,
            color: tpl ? INTENSITY_BAR_CLASS[tpl.intensity] : TIMELINE_MANUAL_CLASS,
            label: `${segment.season.name || t(NS, 'timeline_manual_season', 'Saison')} ${fmtPct(segment.season.pct)}`,
        };
    });

    const chipFor = useMemo(() => templateChipResolver(complete, today, holidays), [complete, today, holidays]);

    return (
        <div className="flex flex-col gap-4">
            <SeasonTemplateGallery
                templates={seasonTemplates}
                today={today}
                chipFor={chipFor}
                onPick={(picked) => handlePickTemplate(picked, templateByName.get(picked.name))}
            />

            <div>
                <Button onClick={handleAddSeason} variant="outline" className="border-secondary text-secondary border" type="button">
                    <PlusIcon className="h-4 w-4" />
                    {t(NS, 'add_season', 'Ajouter une saison')}
                </Button>
            </div>

            {seasons.map((season, index) => (
                <YieldSeasonRow
                    key={index}
                    value={season}
                    today={today}
                    holidays={holidays}
                    onChange={(patch) => handleSeasonChange(index, patch)}
                    onRemove={() => removeSeason(index)}
                    autoFocusPct={index === focusPctIndex}
                />
            ))}

            <p className="text-muted-foreground text-xs">
                {t(NS, 'seasons_uncovered_hint', 'Les dates hors saison utilisent simplement le prix de base.')}
            </p>

            <SeasonTimeline today={today} horizon={horizon} segments={timelineSegments} />
        </div>
    );
}
