import { apiFetch } from '@/lib/loading/api-fetch';
import { cn } from '@/lib/utils';
import type { PreviewResponse } from '@/types/automatisations';
import { Eye, Loader2 } from 'lucide-react';
import { useEffect, useState } from 'react';
import { fill, formatDateTimeShort, TONE_CLASSES } from './automatisations-format';
import { errorText, type Translate } from './labels';
import type { RulePayload } from './rule-form';

const NS = 'automatisations';

/** Délai après la dernière frappe avant de recalculer l'aperçu. */
export const PREVIEW_DEBOUNCE_MS = 600;

type PreviewState =
    | { kind: 'idle' }
    | { kind: 'incomplete' }
    | { kind: 'loading' }
    | { kind: 'ready'; data: PreviewResponse }
    | { kind: 'error'; message: string };

interface Props {
    /** La règle telle qu'elle serait enregistrée ; null quand le formulaire est incomplet. */
    payload: RulePayload | null;
    enabled: boolean;
    t: Translate;
}

/**
 * L'aperçu de la règle en cours d'écriture : combien de réservations elle
 * toucherait dans les 14 prochains jours, et le message RÉEL de 1 à 3
 * réservations à venir. Une variable vide est dite en rouge : ce message ne
 * partirait pas (le moteur l'écarterait).
 *
 * Appel JSON débouncé (600 ms), le précédent annulé à chaque changement.
 */
export function RulePreview({ payload, enabled, t }: Props) {
    const [state, setState] = useState<PreviewState>({ kind: 'idle' });
    const key = payload ? JSON.stringify(payload) : null;

    useEffect(() => {
        if (!enabled) return;
        if (key === null) {
            setState({ kind: 'incomplete' });
            return;
        }

        const controller = new AbortController();
        setState({ kind: 'loading' });

        const timer = window.setTimeout(async () => {
            try {
                const response = await apiFetch(route('automatisations.rules.preview'), {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
                    body: key,
                    signal: controller.signal,
                });

                if (response.status === 422) {
                    const body = (await response.json()) as { errors?: Record<string, string[]> };
                    const first = Object.values(body.errors ?? {})[0]?.[0];
                    setState({ kind: 'error', message: first ?? t(NS, 'preview_error', 'Aperçu indisponible pour le moment.') });
                    return;
                }

                if (!response.ok) {
                    setState({ kind: 'error', message: t(NS, 'preview_error', 'Aperçu indisponible pour le moment.') });
                    return;
                }

                setState({ kind: 'ready', data: (await response.json()) as PreviewResponse });
            } catch {
                // Annulé par une frappe plus récente : l'appel suivant répondra.
                if (controller.signal.aborted) return;
                setState({ kind: 'error', message: t(NS, 'preview_error', 'Aperçu indisponible pour le moment.') });
            }
        }, PREVIEW_DEBOUNCE_MS);

        return () => {
            window.clearTimeout(timer);
            controller.abort();
        };
        // `t` change d'identité à chaque rendu ; seule la règle doit relancer l'appel.
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [key, enabled]);

    return (
        <section className="flex flex-col gap-2 rounded-lg border p-3">
            <h4 className="flex items-center gap-2 text-sm font-medium">
                <Eye className="h-4 w-4" aria-hidden="true" />
                {t(NS, 'preview_title', 'Aperçu')}
                {state.kind === 'loading' && (
                    <Loader2
                        className="text-muted-foreground h-3.5 w-3.5 animate-spin"
                        aria-label={t(NS, 'preview_loading', 'Calcul de l’aperçu…')}
                    />
                )}
            </h4>

            {state.kind === 'incomplete' && (
                <p className="text-muted-foreground text-xs">
                    {t(NS, 'preview_incomplete', 'L’aperçu apparaît dès que le moment, les provenances, les logements et un texte sont valides.')}
                </p>
            )}

            {state.kind === 'error' && <p className="text-xs text-red-600">{errorText(state.message, t)}</p>}

            {state.kind === 'ready' && (
                <>
                    <p className="text-sm">
                        {fill(
                            state.data.forecastCount > 1
                                ? t(NS, 'preview_forecast_plural', 'Concerne :count réservations dans les 14 prochains jours')
                                : t(NS, 'preview_forecast', 'Concerne :count réservation dans les 14 prochains jours'),
                            { count: state.data.forecastCount },
                        )}
                    </p>
                    {state.data.samples.length === 0 ? (
                        <p className="text-muted-foreground text-xs">
                            {t(NS, 'preview_no_sample', 'Aucune réservation à venir dans ce périmètre pour montrer le message.')}
                        </p>
                    ) : (
                        <ul className="flex flex-col gap-2">
                            {state.data.samples.map((sample, index) => (
                                <li key={`${sample.reservationLabel}-${index}`} className="bg-muted/30 rounded-md border p-2.5">
                                    <p className="text-muted-foreground flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs">
                                        <span className="text-foreground font-medium">{sample.reservationLabel}</span>
                                        {sample.propertyName && <span>{sample.propertyName}</span>}
                                        {sample.checkIn && (
                                            <span>{fill(t(NS, 'preview_check_in', 'arrivée le :date'), { date: sample.checkIn })}</span>
                                        )}
                                        <span className="rounded border px-1 text-[10px] uppercase">{sample.language}</span>
                                        {sample.scheduledAt ? (
                                            <span className="text-foreground font-medium">
                                                {fill(t(NS, 'preview_scheduled', 'prévu le :date'), {
                                                    date: formatDateTimeShort(sample.scheduledAt),
                                                })}
                                            </span>
                                        ) : (
                                            // Réservation ajoutée pour MONTRER le texte : son moment
                                            // tombe hors des 14 jours — elle n'est pas comptée
                                            // ci-dessus et rien n'est préparé pour elle maintenant.
                                            <span className="italic">
                                                {t(NS, 'preview_example_only', 'exemple de rendu — pas de message dans les 14 prochains jours')}
                                            </span>
                                        )}
                                    </p>
                                    {sample.text !== null ? (
                                        <p className="mt-1.5 text-sm whitespace-pre-wrap">{sample.text}</p>
                                    ) : (
                                        <p className={cn('mt-1.5 rounded border px-2 py-1 text-xs font-medium', TONE_CLASSES.red)}>
                                            {sample.missing.length > 0
                                                ? fill(t(NS, 'preview_missing', 'Ce message ne partirait pas : :vars manquant(s)'), {
                                                      vars: sample.missing.join(', '),
                                                  })
                                                : t(NS, 'preview_no_text', 'Aucun texte pour la langue de ce voyageur.')}
                                        </p>
                                    )}
                                </li>
                            ))}
                        </ul>
                    )}
                </>
            )}
        </section>
    );
}
