import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import SearchableSelect from '@/components/ui/select-search';
import { Spinner } from '@/components/ui/spinner';
import { cn } from '@/lib/utils';
import { Link } from '@inertiajs/react';
import { TriangleAlert } from 'lucide-react';
import type { ReactNode } from 'react';
import { fmtDate, fmtMontant, fmtNombre } from '../format';
import type { Devise, LogementChoix, SejourRapport } from '../types';

/**
 * Ligne « séjour » d'un rapport de versement Airbnb, partagée par les deux
 * panneaux qui en montrent : le rapport Airbnb seul (une case par séjour) et
 * le relevé bancaire (séjours rangés sous leur versement, montant en dinars).
 * Aucun montant n'est calculé ici : tout vient du serveur.
 */

export type Tr = (cle: string, fr: string) => string;

export function Point() {
    return (
        <span className="text-muted-foreground" aria-hidden>
            ·
        </span>
    );
}

interface SejourLigneProps {
    sejour: SejourRapport & { ht_tnd?: number | null };
    devise: Devise;
    logements: LogementChoix[];
    tr: Tr;
    /** Le séjour compte (cochable, ou facturable sous son versement) ; sinon la ligne est grisée. */
    actif: boolean;
    occupe: boolean;
    /** « Changer » a été cliqué : le choix du logement est ouvert. */
    enEdition: boolean;
    /** Le recalcul de CE séjour est en cours. */
    enRecalcul: boolean;
    onEdition: (ouverte: boolean) => void;
    onAffecter: (logementId: number) => void;
    /** Case à cocher du séjour (rapport Airbnb). Absente quand la sélection se fait plus haut (relevé : par versement). */
    selection?: { cochee: boolean; onBasculer: () => void };
    /** Relevé bancaire : la ligne HT en dinars (`ht_tnd`) à droite, le HT d'origine dessous. */
    enDinars?: boolean;
}

export function SejourLigne({
    sejour: s,
    devise,
    logements,
    tr,
    actif,
    occupe,
    enEdition,
    enRecalcul,
    onEdition,
    onAffecter,
    selection,
    enDinars = false,
}: SejourLigneProps) {
    const ouvert = enEdition || (s.logement === null && s.deja_facturee === null);

    return (
        <li
            onClick={selection ? () => actif && !occupe && selection.onBasculer() : undefined}
            className={cn(
                'grid gap-x-3 px-3 py-3',
                selection ? 'grid-cols-[auto_minmax(0,1fr)_auto]' : 'grid-cols-[minmax(0,1fr)_auto]',
                actif ? selection && 'hover:bg-muted/30 cursor-pointer' : 'bg-muted/20',
            )}
        >
            {selection && (
                <Checkbox
                    checked={selection.cochee}
                    disabled={!actif || occupe}
                    onClick={(e) => e.stopPropagation()}
                    onCheckedChange={() => selection.onBasculer()}
                    aria-label={s.voyageur}
                    className="mt-0.5"
                />
            )}
            <div className="grid min-w-0 gap-1">
                <div className="flex flex-wrap items-center gap-x-2 gap-y-0.5">
                    {s.logement ? (
                        <span className="truncate text-sm font-medium" title={s.logement.nom}>
                            {s.logement.nom}
                        </span>
                    ) : (
                        <span className="text-sm font-medium text-rose-700">{tr('rapport.logement_inconnu', 'Logement à choisir')}</span>
                    )}
                    {s.logement?.proprietaire && (
                        <span className="text-muted-foreground truncate text-xs">
                            {tr('rapport.prop', 'prop. :nom').replace(':nom', s.logement.proprietaire)}
                        </span>
                    )}
                    <Puce s={s} tr={tr} />
                    {s.logement && !ouvert && s.deja_facturee === null && (
                        <button
                            type="button"
                            className="text-secondary text-xs hover:underline disabled:opacity-50"
                            disabled={occupe}
                            onClick={(e) => {
                                e.stopPropagation();
                                onEdition(true);
                            }}
                        >
                            {tr('rapport.changer', 'Changer')}
                        </button>
                    )}
                </div>
                <div className="text-muted-foreground text-xs">
                    {s.voyageur} · {fmtDate(s.arrivee).slice(0, 5)} → {fmtDate(s.depart)}
                    {s.nuits !== null && ` · ${s.nuits} ${s.nuits > 1 ? tr('rapport.nuits', 'nuits') : tr('rapport.nuit', 'nuit')}`}
                    <span className="hidden sm:inline"> · « {s.annonce} »</span>
                </div>
                <Calcul s={s} devise={devise} tr={tr} />
                {s.avertissements.map((a) => (
                    <div key={a} className="flex items-start gap-1 text-xs text-amber-800">
                        <TriangleAlert className="mt-0.5 size-3 shrink-0" aria-hidden />
                        {a}
                    </div>
                ))}
                {s.erreur && <div className="text-xs text-rose-700">{s.erreur}</div>}
                {s.deja_facturee && (
                    <Link
                        href={route('factures.edit', s.deja_facturee.id)}
                        onClick={(e) => e.stopPropagation()}
                        className="text-secondary w-fit text-xs hover:underline"
                    >
                        {s.deja_facturee.numero
                            ? tr('commission.deja_sur', 'déjà sur :numero').replace(':numero', s.deja_facturee.numero)
                            : tr('commission.deja_brouillon', 'déjà dans un brouillon')}
                    </Link>
                )}
                {ouvert && (
                    <div className="flex max-w-md items-center gap-2 pt-1" onClick={(e) => e.stopPropagation()}>
                        <div className="min-w-0 flex-1">
                            <SearchableSelect
                                value={s.logement ? String(s.logement.id) : undefined}
                                onValueChange={(v) => onAffecter(Number(v))}
                                items={logements}
                                placeholder={tr('rapport.choisir_logement', 'Choisir le logement…')}
                                notFoundMessage={tr('rapport.aucun_logement', 'Aucun logement trouvé')}
                                className="h-8 w-full rounded-md bg-white text-sm"
                            />
                        </div>
                        {enRecalcul && <Spinner size="sm" />}
                        {enEdition && !enRecalcul && (
                            <Button type="button" variant="ghost" size="sm" onClick={() => onEdition(false)}>
                                {tr('import.annuler', 'Annuler')}
                            </Button>
                        )}
                    </div>
                )}
            </div>
            {enDinars ? (
                <div className="text-right tabular-nums">
                    <div className="text-sm font-semibold whitespace-nowrap">{typeof s.ht_tnd === 'number' ? fmtMontant(s.ht_tnd, 'TND') : '—'}</div>
                    {s.ht !== null && (
                        <div className="text-muted-foreground text-[11px] whitespace-nowrap">
                            {tr('releve.ht_origine', ':montant HT').replace(':montant', fmtMontant(s.ht, devise))}
                        </div>
                    )}
                </div>
            ) : (
                <div className="text-right tabular-nums">
                    <div className="text-sm font-semibold whitespace-nowrap">{s.ht !== null ? fmtMontant(s.ht, devise) : '—'}</div>
                    {s.ttc !== null && (
                        <div className="text-muted-foreground text-[11px] whitespace-nowrap">
                            {tr('rapport.ttc', ':montant TTC').replace(':montant', fmtMontant(s.ttc, devise))}
                        </div>
                    )}
                </div>
            )}
        </li>
    );
}

/** D'où vient le logement : la réservation (neutre), le nom de l'annonce (à vérifier), ou un choix. */
export function Puce({ s, tr }: { s: SejourRapport; tr: Tr }) {
    if (s.logement_origine === null) return null;

    const [libelle, classes] =
        s.logement_origine === 'reservation'
            ? [
                  tr('rapport.via_reservation', 'Réservation :ref').replace(':ref', s.reservation?.reference ?? ''),
                  'bg-slate-100 text-slate-700 ring-slate-200',
              ]
            : s.logement_origine === 'annonce'
              ? [tr('rapport.via_annonce', 'Reconnu par l’annonce'), 'bg-amber-50 text-amber-800 ring-amber-200']
              : [tr('rapport.via_manuel', 'Choisi à la main'), 'bg-slate-100 text-slate-700 ring-slate-200'];

    return <span className={cn('rounded-full px-2 py-0.5 text-[11px] font-medium ring-1 ring-inset', classes)}>{libelle}</span>;
}

/** Le calcul de la ligne, en clair : c'est ce que l'on relit avant de créer le brouillon. */
export function Calcul({ s, devise, tr }: { s: SejourRapport; devise: Devise; tr: Tr }) {
    if (s.ttc === null) return null;

    // Montants toujours au centime (« 673,20 », pas « 673,2 ») ; taux au plus juste.
    const n = (v: number) => v.toLocaleString('fr-FR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
    const pct = (v: number) => fmtNombre(v, 2);
    const resultat = (
        <>
            {' = '}
            <span className="text-foreground font-medium">{fmtMontant(s.ttc, devise)}</span> TTC
        </>
    );

    let detail: ReactNode;
    // Deuxième ligne, toujours visible (un survol ne se découvre pas, et
    // n'existe pas sur téléphone) : d'où vient le ménage, ou pourquoi un
    // versement partagé ne dépend pas du logement.
    let note: string | null = null;
    if (s.partage) {
        note = tr(
            'rapport.note_partage',
            'Airbnb a déjà versé sa part au propriétaire : la ligne reprend ce qui nous est resté, quel que soit le logement.',
        );
        detail = (
            <>
                {tr('rapport.calcul_partage', 'Partagé par Airbnb, reçu :reservation − :cohote')
                    .replace(':reservation', n(s.montant_reservation))
                    .replace(':cohote', n(-s.montant_cohote))}
                {resultat}
                {s.ttc_regle !== null && (
                    <span className="text-muted-foreground">
                        {' · '}
                        {tr('rapport.regle_donnerait', 'la règle donnerait :montant').replace(':montant', fmtMontant(s.ttc_regle, devise))}
                    </span>
                )}
            </>
        );
    } else if (s.regle === 'pourcentage') {
        detail = (
            <>
                {tr('rapport.calcul_pourcentage', ':pct % × :base').replace(':pct', pct(s.pourcentage)).replace(':base', n(s.base))}
                {resultat}
            </>
        );
    } else {
        // D'où vient le ménage : le frais du logement, ou les dinars du Manager reconvertis.
        const origineMenage =
            s.menage_source === 'frais'
                ? tr('rapport.menage_frais', 'Frais de ménage du logement')
                : s.menage_taux !== null && (s.menage_source === 'synchro' || s.menage_source === 'proprietaire')
                  ? (s.menage_source === 'synchro'
                        ? tr('rapport.menage_synchro', ':tnd TND ÷ :taux (taux client de la synchronisation)')
                        : tr('rapport.menage_proprietaire', ':tnd TND ÷ :taux (taux propriétaire)')
                    )
                        .replace(':tnd', s.menage_tnd.toLocaleString('fr-FR', { minimumFractionDigits: 3, maximumFractionDigits: 3 }))
                        .replace(':taux', fmtNombre(s.menage_taux, 3))
                  : undefined;
        if (s.menage !== null && origineMenage) {
            note = tr('rapport.menage_ligne', 'Ménage :menage — :origine')
                .replace(':menage', fmtMontant(s.menage, devise))
                .replace(':origine', origineMenage);
        }
        const soulignement = 'decoration-muted-foreground/50 underline decoration-dotted underline-offset-2';
        detail =
            s.regle === 'menage' ? (
                // Ménage seul : le montant EST le ménage, rien à détailler.
                <>
                    <span className={cn('text-foreground font-medium', soulignement)} title={origineMenage}>
                        {fmtMontant(s.ttc, devise)}
                    </span>{' '}
                    TTC
                </>
            ) : (
                <>
                    {tr('rapport.calcul_menage', 'ménage')}{' '}
                    <span className={soulignement} title={origineMenage}>
                        {n(s.menage ?? 0)}
                    </span>{' '}
                    + {pct(s.commission_pct)} %
                    {!s.commission_saisie && <span className="text-muted-foreground"> {tr('rapport.par_defaut', '(par défaut)')}</span>} × (
                    {n(s.base)} − {n(s.menage ?? 0)}){resultat}
                </>
            );
    }

    const regle =
        s.regle === 'menage'
            ? tr('rapport.regle_menage', 'Ménage')
            : s.regle === 'pourcentage'
              ? tr('rapport.regle_pourcentage', ':pct % du montant').replace(':pct', pct(s.pourcentage))
              : tr('rapport.regle_menage_commission', 'Ménage + commission');

    return (
        <div className="text-muted-foreground grid gap-0.5 text-xs tabular-nums">
            <div>
                {!s.partage && <span className="text-foreground/80 font-medium">{regle} : </span>}
                {detail}
            </div>
            {note && <div className="text-[11px]">{note}</div>}
        </div>
    );
}
