import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from '@/components/ui/sheet';
import { Switch } from '@/components/ui/switch';
import { useTranslation } from '@/hooks/use-translation';
import { router } from '@inertiajs/react';
import { useEffect, useState } from 'react';
import { toast } from 'sonner';
import type { SeasonTemplate } from '../../logements/season-range-utils';
import HelpHint from '../components/HelpHint';
import LastMinuteEditor from '../components/rules/LastMinuteEditor';
import ObaEditor from '../components/rules/ObaEditor';
import SeasonsEditor from '../components/rules/SeasonsEditor';
import WeekendEditor from '../components/rules/WeekendEditor';
import { ruleGroupPayload } from '../lib/rule-payloads';
import { normalizeFarOut, normalizeWeekend } from '../lib/rule-sections';
import type { FarOutPremium, LastMinuteRule, MovableHolidays, ObaRule, WeekendRule, YieldRuleGroup, YieldSeasonality } from '../types';

const NS = 'yield.rule_groups';

export interface RuleGroupDefaults {
    seasonality: YieldSeasonality;
    last_minute_rules: LastMinuteRule[];
    far_out_premium: FarOutPremium;
    oba_rules: ObaRule[];
    /** Point de départ d'une section week-end ajoutée au groupe (la suggestion ×1,10, pas le ×1 neutre). */
    weekend_rule: WeekendRule;
}

interface RuleGroupSheetProps {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    /** The group being edited, or null to create a new one. */
    group: YieldRuleGroup | null;
    defaults: RuleGroupDefaults;
    seasonTemplates: SeasonTemplate[];
    /** Dates des fêtes mobiles (config/yield-holidays.php). */
    movableHolidays?: MovableHolidays;
    obaPresets: Record<string, ObaRule[]>;
}

/** A labelled on/off section header that reveals its editor when enabled. */
function SectionToggle({ on, onToggle, title, help, children }: { on: boolean; onToggle: (v: boolean) => void; title: string; help?: string; children: React.ReactNode }) {
    return (
        <div className="rounded-lg border">
            <label className="flex cursor-pointer items-center justify-between gap-2 px-3 py-2.5">
                <span className="text-sm font-medium">
                    {title}
                    {help && <HelpHint text={help} />}
                </span>
                <Switch checked={on} onCheckedChange={onToggle} />
            </label>
            {on && <div className="border-t p-3">{children}</div>}
        </div>
    );
}

/**
 * Create / edit a reusable rule group. Each section toggle, when
 * on, includes that section (built from the shared editors); off = the section
 * is sent as null (not part of the group). Posts to yield.rule-groups.store or
 * .update.
 *
 * Week-end : une section PORTÉE à ×1 n'est pas « absente » — elle coupe la
 * règle chez tous les logements liés. D'où le point de départ ×1,10 d'une
 * section qu'on ajoute (defaults.weekend_rule).
 */
export default function RuleGroupSheet({ open, onOpenChange, group, defaults, seasonTemplates, movableHolidays, obaPresets }: RuleGroupSheetProps) {
    const { t } = useTranslation();

    const [name, setName] = useState('');
    const [description, setDescription] = useState('');
    const [incSeasons, setIncSeasons] = useState(false);
    const [incLastMinute, setIncLastMinute] = useState(false);
    const [incOba, setIncOba] = useState(false);
    const [incWeekend, setIncWeekend] = useState(false);
    const [seasonality, setSeasonality] = useState<YieldSeasonality>(defaults.seasonality);
    const [lastMinute, setLastMinute] = useState<LastMinuteRule[]>(defaults.last_minute_rules);
    const [farOut, setFarOut] = useState<FarOutPremium>(defaults.far_out_premium);
    const [oba, setOba] = useState<ObaRule[]>(defaults.oba_rules);
    const [weekend, setWeekend] = useState<WeekendRule>(() => normalizeWeekend(defaults.weekend_rule));
    const [processing, setProcessing] = useState(false);
    const [nameError, setNameError] = useState(false);
    const [errors, setErrors] = useState<Record<string, string>>({});

    // Seed the form whenever the sheet opens for a new target.
    useEffect(() => {
        if (!open) return;
        setNameError(false);
        setErrors({});
        setName(group?.name ?? '');
        setDescription(group?.description ?? '');
        setIncSeasons(!!group?.seasonality);
        setIncLastMinute(!!group?.last_minute_rules);
        setIncOba(!!group?.oba_rules);
        setIncWeekend(!!group?.weekend_rule);
        setSeasonality(group?.seasonality ?? defaults.seasonality);
        setLastMinute(group?.last_minute_rules ?? defaults.last_minute_rules);
        // Une prime de groupe sans clés ([] de PHP) devient la forme neutre
        // affichable, au lieu d'un champ vide et d'une aide « ×NaN ».
        setFarOut(normalizeFarOut(group?.far_out_premium ?? defaults.far_out_premium));
        setOba(group?.oba_rules ?? defaults.oba_rules);
        setWeekend(normalizeWeekend(group?.weekend_rule ?? defaults.weekend_rule));
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [open, group]);

    const submit = () => {
        if (name.trim() === '') {
            setNameError(true);
            return;
        }
        setProcessing(true);
        setErrors({});
        // Les cinq sections, `null` quand l'interrupteur est coupé (ruleGroupPayload,
        // testée). Nested rule sections are typed as interfaces, which aren't
        // assignable to Inertia's recursive FormDataConvertible index signature —
        // cast to the router's expected payload type (values are plain JSON at runtime).
        const payload = ruleGroupPayload({
            name,
            description,
            include: { seasonality: incSeasons, lastMinute: incLastMinute, oba: incOba, weekend: incWeekend },
            seasonality,
            lastMinute,
            farOut,
            oba,
            weekend,
        }) as unknown as Parameters<typeof router.post>[1];
        const opts = {
            preserveScroll: true,
            onSuccess: () => {
                toast.success(group ? t(NS, 'toast_updated', 'Groupe mis à jour.') : t(NS, 'toast_created', 'Groupe créé.'));
                onOpenChange(false);
            },
            // Surface the actual validation reasons instead of a generic toast.
            onError: (errs: Record<string, string>) => {
                setErrors(errs);
                const first = Object.values(errs)[0];
                toast.error(first ?? t(NS, 'toast_error', 'Une erreur est survenue.'));
            },
            onFinish: () => setProcessing(false),
        };
        if (group) {
            router.put(route('yield.rule-groups.update', group.id), payload, opts);
        } else {
            router.post(route('yield.rule-groups.store'), payload, opts);
        }
    };

    return (
        <Sheet open={open} onOpenChange={onOpenChange}>
            <SheetContent side="right" className="flex w-[min(96vw,640px)] flex-col p-0 sm:max-w-none">
                <SheetHeader className="border-b">
                    <SheetTitle>{group ? t(NS, 'edit_title', 'Modifier le groupe') : t(NS, 'create_title', 'Nouveau groupe de règles')}</SheetTitle>
                    <SheetDescription>{t(NS, 'sheet_description', 'Active les sections que ce groupe doit piloter. Les logements liés suivent automatiquement.')}</SheetDescription>
                </SheetHeader>

                <div className="flex flex-1 flex-col gap-4 overflow-y-auto p-4">
                    {Object.keys(errors).length > 0 && (
                        <div className="rounded-md border border-red-300 bg-red-50 px-3 py-2 text-xs text-red-700 dark:border-red-900/40 dark:bg-red-950/30 dark:text-red-300">
                            <p className="font-medium">{t(NS, 'errors_title', 'Impossible d’enregistrer :')}</p>
                            <ul className="mt-1 list-disc pl-4">
                                {Object.values(errors).map((m, i) => (
                                    <li key={i}>{m}</li>
                                ))}
                            </ul>
                        </div>
                    )}

                    <div className="flex flex-col gap-1">
                        <Label htmlFor="rg_name" className="text-xs">{t(NS, 'name', 'Nom')}</Label>
                        <Input id="rg_name" value={name} onChange={(e) => setName(e.target.value)} placeholder={t(NS, 'name_placeholder', 'Ex. Été agressif, Studios centre-ville…')} />
                        {nameError && <p className="text-xs text-red-500">{t(NS, 'name_required', 'Le nom est obligatoire.')}</p>}
                    </div>
                    <div className="flex flex-col gap-1">
                        <Label htmlFor="rg_desc" className="text-xs">{t(NS, 'description', 'Description (optionnel)')}</Label>
                        <Input id="rg_desc" value={description} onChange={(e) => setDescription(e.target.value)} />
                    </div>

                    <SectionToggle
                        on={incSeasons}
                        onToggle={setIncSeasons}
                        title={t(NS, 'section_seasons', 'Saisons')}
                        help={t(NS, 'section_seasons_help', 'Ajustements de prix par plages de dates.')}
                    >
                        <SeasonsEditor value={seasonality} onChange={setSeasonality} seasonTemplates={seasonTemplates} holidays={movableHolidays} />
                    </SectionToggle>

                    <SectionToggle
                        on={incLastMinute}
                        onToggle={setIncLastMinute}
                        title={t(NS, 'section_lastminute', 'Last-minute & far-out')}
                        help={t(NS, 'section_lastminute_help', 'Rabais sur les nuits proches encore libres + premium longue échéance.')}
                    >
                        <LastMinuteEditor lastMinute={lastMinute} farOut={farOut} onChangeLastMinute={setLastMinute} onChangeFarOut={setFarOut} />
                    </SectionToggle>

                    <SectionToggle
                        on={incOba}
                        onToggle={setIncOba}
                        title={t(NS, 'section_oba', 'OBA (occupation)')}
                        help={t(NS, 'section_oba_help', 'Monte le prix quand la période se remplit — jamais de baisse.')}
                    >
                        <ObaEditor value={oba} onChange={setOba} presets={obaPresets} />
                    </SectionToggle>

                    <SectionToggle
                        on={incWeekend}
                        onToggle={setIncWeekend}
                        title={t(NS, 'section_weekend', 'Week-end')}
                        help={t(NS, 'section_weekend_help', 'Un multiplicateur sur les nuits choisies (par défaut vendredi et samedi). Porté à ×1, il COUPE la règle chez les logements liés.')}
                    >
                        <WeekendEditor value={weekend} onChange={setWeekend} />
                    </SectionToggle>
                </div>

                <SheetFooter className="flex-row justify-end border-t">
                    <Button variant="outline" onClick={() => onOpenChange(false)}>{t(NS, 'cancel', 'Annuler')}</Button>
                    <Button onClick={submit} disabled={processing}>{t(NS, 'save', 'Enregistrer')}</Button>
                </SheetFooter>
            </SheetContent>
        </Sheet>
    );
}
