import { Button } from '@/components/ui/button';
import { Sheet, SheetContent, SheetFooter, SheetHeader, SheetTitle } from '@/components/ui/sheet';
import { useTranslation } from '@/hooks/use-translation';
import { Loader2 } from 'lucide-react';
import { useEffect, useState } from 'react';
import type { SeasonTemplate } from '../../logements/season-range-utils';
import { initialPreviewPayload } from '../lib/rule-payloads';
import { getYieldJson, postYieldJson } from '../lib/yield-api';
import type { MovableHolidays, PriceDay, RuleSectionValues } from '../types';
import PriceCalendarPreview from './PriceCalendarPreview';
import YieldRuleEditor, { type YieldConfigData } from './YieldRuleEditor';

interface YieldConfigResponse {
    config: YieldConfigData;
    obaPresets: Record<string, YieldConfigData['oba_rules']>;
    /** Recurring season templates from config/season-templates.php. */
    seasonTemplates: SeasonTemplate[];
    /** Dates des fêtes mobiles (config/yield-holidays.php). */
    movableHolidays?: MovableHolidays;
    /** Défauts / formes neutres des sections, pour l'interrupteur « Règle active ». */
    sectionDefaults: RuleSectionValues;
    sectionDisabled: RuleSectionValues;
}

interface YieldRuleSheetProps {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    /** Yield config id whose rules to edit. Null while nothing is selected. */
    configId: number | null;
    exchangeRate: number;
    /** Forwarded from the editor, keyed by the property uid so a parent (table) can update that row. */
    onPreview?: (uid: string, preview: PriceDay[]) => void;
    /** Called after a successful save. */
    onSaved?: () => void;
}

/**
 * Right-hand slide-over for editing a logement's yield rules without leaving
 * the current page. Lazily fetches GET yield.config when opened, then renders a
 * 2-pane layout: the shared {@link YieldRuleEditor} (left, scrollable) and a
 * FIXED {@link PriceCalendarPreview} (right) that stays visible across the
 * editor's rule tabs and updates live as rules change.
 */
export default function YieldRuleSheet({ open, onOpenChange, configId, exchangeRate, onPreview, onSaved }: YieldRuleSheetProps) {
    const { t } = useTranslation();
    const [loading, setLoading] = useState(false);
    const [data, setData] = useState<YieldConfigResponse | null>(null);
    const [error, setError] = useState(false);

    // Live state mirrored from the editor so the sheet's own calendar (right
    // pane) stays in sync as rules are edited, regardless of the active tab.
    const [livePreview, setLivePreview] = useState<PriceDay[]>([]);
    const [basePrice, setBasePrice] = useState<number>(0);
    /** L'aperçu affiché est-il figé (dernier calcul valide) ? Voir YieldRuleEditor. */
    const [previewStale, setPreviewStale] = useState(false);

    useEffect(() => {
        if (!open || configId == null) {
            return;
        }

        let cancelled = false;
        setLoading(true);
        setError(false);
        setData(null);
        setLivePreview([]);
        setPreviewStale(false);

        (async () => {
            const configResult = await getYieldJson<YieldConfigResponse>(route('yield.config', configId));
            if (cancelled) return;

            if (!configResult.ok) {
                setError(true);
                setLoading(false);
                return;
            }

            const result = configResult.data;
            setData(result);
            setBasePrice(result.config.base_price);

            // Amorçage du calendrier pour que le panneau de droite ne soit pas
            // vide avant le premier aperçu débouncé de l'éditeur.
            //
            // On teste le statut AVANT de lire le corps : depuis que l'aperçu a
            // un Form Request, un 422 ne porte pas de `preview`, et l'affecter
            // tel quel plantait le calendrier au rendu. Un échec ici n'est pas
            // fatal — l'éditeur affichera la raison exacte à son premier calcul.
            //
            // Même corps et mêmes normalisations que l'éditeur (une prime sans
            // clés [] de PHP part sous sa forme neutre, un week-end absent à ×1) :
            // initialPreviewPayload, testée.
            const previewResult = await postYieldJson<{ preview: PriceDay[] }>(
                route('yield.preview', configId),
                initialPreviewPayload(result.config),
            );
            if (cancelled) return;

            // On ne rend l'éditeur qu'une fois l'amorçage tenté : sinon le
            // panneau de droite afficherait brièvement son état vide.
            setLoading(false);

            if (!previewResult.ok) return;

            const preview = Array.isArray(previewResult.data?.preview) ? previewResult.data.preview : [];
            setLivePreview(preview);
            onPreview?.(result.config.property_id, preview);
        })();

        return () => {
            cancelled = true;
        };
        // onPreview is intentionally excluded — re-fetching on a parent callback
        // identity change would needlessly reload the config.
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [open, configId]);

    return (
        <Sheet open={open} onOpenChange={onOpenChange}>
            <SheetContent side="right" className="flex w-[min(98vw,1400px)] flex-col p-0 sm:max-w-none">
                <SheetHeader className="border-b">
                    <SheetTitle>{data?.config.property_name ?? t('yield.index', 'price_config_title', 'Configuration du prix')}</SheetTitle>
                </SheetHeader>

                {loading && (
                    <div className="text-muted-foreground flex flex-1 items-center justify-center gap-2 text-sm">
                        <Loader2 className="h-4 w-4 animate-spin" />
                        {t('yield.index', 'loading', 'Chargement…')}
                    </div>
                )}

                {error && !loading && (
                    <p className="text-destructive flex flex-1 items-center justify-center px-4 text-center text-sm">
                        {t('yield.index', 'config_load_failed', 'Impossible de charger la configuration.')}
                    </p>
                )}

                {data && !loading && (
                    <div className="grid min-h-0 flex-1 lg:grid-cols-2">
                        {/* LEFT pane: scrollable rule editor (owns the Tabs + Save). */}
                        <div className="min-h-0 overflow-y-auto border-r p-4">
                            <YieldRuleEditor
                                config={data.config}
                                obaPresets={data.obaPresets}
                                exchangeRate={exchangeRate}
                                seasonTemplates={data.seasonTemplates}
                                movableHolidays={data.movableHolidays}
                                sectionDefaults={data.sectionDefaults}
                                sectionDisabled={data.sectionDisabled}
                                onPreview={(preview) => {
                                    setLivePreview(preview);
                                    onPreview?.(data.config.property_id, preview);
                                }}
                                onPreviewStale={setPreviewStale}
                                onBasePriceChange={setBasePrice}
                                onSaved={() => {
                                    onSaved?.();
                                    onOpenChange(false);
                                }}
                            />
                        </div>

                        {/* RIGHT pane: FIXED live calendar — lives OUTSIDE the Tabs so it
                            never scrolls away or unmounts when the active tab changes. */}
                        <div className="bg-muted/20 min-h-0 overflow-y-auto p-4">
                            <h3 className="mb-3 text-sm font-medium">{t('yield.index', 'price_preview_title', 'Preview des prix (90 jours)')}</h3>
                            <PriceCalendarPreview preview={livePreview} exchangeRate={exchangeRate} basePrice={basePrice} stale={previewStale} />
                        </div>
                    </div>
                )}

                <SheetFooter className="flex-row justify-end border-t">
                    <Button variant="outline" onClick={() => onOpenChange(false)}>
                        {t('yield.index', 'close', 'Fermer')}
                    </Button>
                </SheetFooter>
            </SheetContent>
        </Sheet>
    );
}
