import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { cn } from '@/lib/utils';
import type { SendRow } from '@/types/automatisations';
import { Link } from '@inertiajs/react';
import { AlertTriangle, CalendarDays, CheckCircle2, Copy, Mail, MessageCircle, MinusCircle, XCircle, type LucideIcon } from 'lucide-react';
import { toast } from 'sonner';
import {
    dateAndTime,
    fill,
    formatDateTimeShort,
    formatDelay,
    isUnknownResult,
    linkParts,
    sendDelayMinutes,
    sendTimeline,
    statusTone,
    TONE_CLASSES,
    type StatusTone,
    type TimelineKind,
} from './automatisations-format';
import type { Translate } from './labels';
import { StatusChip } from './StatusChip';

const NS = 'automatisations';

interface Props {
    send: SendRow | null;
    onClose: () => void;
    t: Translate;
}

const TONE_ICON: Record<StatusTone, LucideIcon> = {
    green: CheckCircle2,
    amber: AlertTriangle,
    red: XCircle,
    gray: MinusCircle,
};

// Classes écrites en entier : Tailwind ne garde au build que ce qu'il lit tel quel.
const STEP_TEXT: Record<StatusTone, string> = {
    green: 'text-emerald-700 dark:text-emerald-300',
    amber: 'text-amber-700 dark:text-amber-300',
    red: 'text-red-700 dark:text-red-300',
    gray: 'text-gray-600 dark:text-gray-300',
};

const STEP_DOT: Record<StatusTone, string> = {
    green: 'border-emerald-600 dark:border-emerald-400',
    amber: 'border-amber-600 dark:border-amber-400',
    red: 'border-red-600 dark:border-red-400',
    gray: 'border-gray-500 dark:border-gray-400',
};

/** Ce qui s'est passé, en une phrase, puis le détail (qui, quand, quoi faire). */
function outcome(send: SendRow, t: Translate): { title: string; detail: string[] } {
    const sent = dateAndTime(send.sentAt ?? send.updatedAt);

    switch (send.status) {
        case 'sent': {
            const when = { date: sent?.date ?? '', time: sent?.time ?? '' };
            const title =
                send.channel === 'email'
                    ? fill(t(NS, 'outcome_sent_email', 'Envoyé par e-mail le :date à :time'), when)
                    : send.channelLabel
                      ? fill(t(NS, 'outcome_sent_on', 'Envoyé sur :channel le :date à :time'), { ...when, channel: send.channelLabel })
                      : fill(t(NS, 'outcome_sent', 'Envoyé le :date à :time'), when);
            const delay = sendDelayMinutes(send);
            const detail = [
                send.approvedBy
                    ? fill(t(NS, 'outcome_approved_by', 'Relu et validé par :name'), { name: send.approvedBy })
                    : t(NS, 'outcome_auto', 'Parti seul, sans relecture (règle automatique)'),
            ];
            if (delay !== null) {
                detail.push(
                    delay === 0
                        ? t(NS, 'outcome_on_time', 'À l’heure prévue')
                        : fill(t(NS, 'outcome_delay', ':delay après l’heure prévue'), { delay: formatDelay(delay) }),
                );
            }

            return { title, detail };
        }
        case 'failed':
            return isUnknownResult(send.reason)
                ? {
                      title: t(NS, 'outcome_unknown', 'Résultat inconnu : le message a peut-être été reçu'),
                      detail: [send.reason ?? '', t(NS, 'outcome_unknown_hint', 'Vérifiez la conversation avant de renvoyer.')].filter(Boolean),
                  }
                : {
                      title: t(NS, 'outcome_failed', 'Échec : rien n’est parti'),
                      detail: [send.reason ?? '', t(NS, 'outcome_failed_hint', 'Vous pouvez le renvoyer depuis « À traiter ».')].filter(Boolean),
                  };
        case 'retry':
            return { title: t(NS, 'outcome_retry', 'Nouvel essai au prochain passage'), detail: [send.reason ?? ''].filter(Boolean) };
        case 'skipped':
            return { title: t(NS, 'outcome_skipped', 'Écarté : rien n’est parti'), detail: [send.reason ?? ''].filter(Boolean) };
        case 'cancelled':
            return { title: t(NS, 'outcome_cancelled', 'Annulé : rien n’est parti'), detail: [send.reason ?? ''].filter(Boolean) };
        case 'pending_approval':
            return {
                title: t(NS, 'outcome_pending', 'En attente de validation'),
                detail: [t(NS, 'outcome_pending_hint', 'À relire et envoyer depuis « À traiter ».')],
            };
        case 'waiting_channel':
            return { title: t(NS, 'outcome_waiting', 'En attente de la conversation du canal'), detail: [send.reason ?? ''].filter(Boolean) };
    }
}

function stepLabel(kind: TimelineKind, t: Translate): string {
    const labels: Record<TimelineKind, [string, string]> = {
        scheduled: ['timeline_scheduled', 'Prévu'],
        prepared: ['timeline_prepared', 'Préparé'],
        sent: ['timeline_sent', 'Envoyé'],
        failed: ['timeline_failed', 'Échec'],
        retry: ['timeline_retry', 'Nouvel essai prévu'],
        skipped: ['timeline_skipped', 'Écarté'],
        cancelled: ['timeline_cancelled', 'Annulé'],
        pending: ['timeline_pending', 'En attente de validation'],
        waiting: ['timeline_waiting', 'En attente de la conversation'],
    };
    const [key, fallback] = labels[kind];

    return t(NS, key, fallback);
}

function languageName(language: string | null, t: Translate): string | null {
    if (language === 'fr') return t(NS, 'lang_fr', 'Français');
    if (language === 'en') return t(NS, 'lang_en', 'Anglais');

    return language ? language.toUpperCase() : null;
}

/** Le texte, adresses web cliquables (sans HTML injecté). */
function MessageText({ text, linkClassName }: { text: string; linkClassName: string }) {
    return (
        <>
            {linkParts(text).map((part, index) =>
                part.href ? (
                    <a key={index} href={part.href} target="_blank" rel="noopener noreferrer" className={cn('break-all underline', linkClassName)}>
                        {part.text}
                    </a>
                ) : (
                    <span key={index}>{part.text}</span>
                ),
            )}
        </>
    );
}

/**
 * Le détail d'un message de l'historique, du coup d'œil à l'étude :
 * bandeau du résultat (une phrase), déroulé et détails côte à côte, le message
 * tel que le voyageur l'a reçu, puis les liens vers la réservation et la
 * conversation.
 */
export function SendDetailDialog({ send, onClose, t }: Props) {
    const copy = async (text: string) => {
        try {
            if (!navigator.clipboard) throw new Error('clipboard unavailable');
            await navigator.clipboard.writeText(text);
            toast.success(t(NS, 'templates_copied', 'Texte copié'));
        } catch {
            toast.error(t(NS, 'templates_copy_failed', 'Le navigateur a refusé la copie : sélectionnez le texte et copiez-le à la main.'));
        }
    };

    return (
        <Dialog open={send !== null} onOpenChange={(value) => !value && onClose()}>
            <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-2xl">
                {send && <SendDetail send={send} t={t} onCopy={copy} />}
            </DialogContent>
        </Dialog>
    );
}

function SendDetail({ send, t, onCopy }: { send: SendRow; t: Translate; onCopy: (text: string) => void }) {
    const tone = statusTone(send.status);
    const ToneIcon = TONE_ICON[tone];
    const result = outcome(send, t);
    const steps = sendTimeline(send);
    const language = languageName(send.language, t);
    const body = send.body?.trim() ?? '';
    const isEmail = send.channel === 'email';

    return (
        <>
            <DialogHeader>
                <DialogTitle className="flex flex-wrap items-center gap-2">
                    {send.guestName}
                    <StatusChip status={send.status} t={t} />
                </DialogTitle>
                <DialogDescription>
                    {send.propertyName ?? ''}
                    {send.checkIn && ` · ${fill(t(NS, 'stay_dates', 'Séjour du :from au :to'), { from: send.checkIn, to: send.checkOut ?? '—' })}`}
                </DialogDescription>
            </DialogHeader>

            {/* Le résultat, en une phrase : ce qu'on vient chercher en ouvrant le détail. */}
            <div className={cn('flex items-start gap-2.5 rounded-md border px-3 py-2.5 text-sm', TONE_CLASSES[tone])}>
                <ToneIcon className="mt-0.5 h-4 w-4 shrink-0" aria-hidden="true" />
                <div className="min-w-0">
                    <p className="font-medium">{result.title}</p>
                    {result.detail.length > 0 && <p className="break-words opacity-90">{result.detail.join(' · ')}</p>}
                </div>
            </div>

            <div className="grid gap-4 sm:grid-cols-2">
                <section className="min-w-0">
                    <h3 className="text-muted-foreground mb-2 text-xs font-medium">{t(NS, 'timeline_title', 'Déroulé')}</h3>
                    <ol className="flex flex-col gap-2.5 border-l-2 pl-3">
                        {steps.map((step, index) => {
                            const when = formatDateTimeShort(step.at);
                            const isLast = index === steps.length - 1;

                            return (
                                <li key={step.kind} className="relative text-sm">
                                    <span
                                        aria-hidden="true"
                                        className={cn(
                                            'bg-background absolute top-1.5 -left-[17px] h-2 w-2 rounded-full border-2',
                                            step.tone ? STEP_DOT[step.tone] : 'border-muted-foreground/40',
                                        )}
                                    />
                                    <p className={cn(step.tone ? cn('font-medium', STEP_TEXT[step.tone]) : 'text-muted-foreground')}>
                                        {stepLabel(step.kind, t)}
                                        {isLast && step.kind === 'sent' && (
                                            <span className="font-normal">
                                                {' · '}
                                                {send.approvedBy
                                                    ? fill(t(NS, 'timeline_by', 'par :name'), { name: send.approvedBy })
                                                    : t(NS, 'timeline_auto', 'automatiquement')}
                                            </span>
                                        )}
                                    </p>
                                    {when && <p className="tabular-nums">{when}</p>}
                                    {isLast && send.attempts > 1 && (
                                        <p className="text-muted-foreground text-xs">
                                            {fill(t(NS, 'timeline_attempts', ':count tentatives'), { count: send.attempts })}
                                        </p>
                                    )}
                                </li>
                            );
                        })}
                    </ol>
                </section>

                <section className="min-w-0">
                    <h3 className="text-muted-foreground mb-2 text-xs font-medium">{t(NS, 'details_title', 'Détails')}</h3>
                    <dl className="flex flex-col gap-2 text-sm">
                        <div>
                            <dt className="text-muted-foreground text-xs">{t(NS, 'detail_rule', 'Règle')}</dt>
                            <dd className="break-words">
                                {send.ruleDeleted ? (
                                    <>
                                        <span className="text-muted-foreground line-through">{send.ruleName}</span>{' '}
                                        <span className="text-muted-foreground text-xs">{t(NS, 'rule_deleted', 'supprimée')}</span>
                                    </>
                                ) : (
                                    send.ruleName
                                )}
                            </dd>
                        </div>
                        {send.channelLabel && (
                            <div>
                                <dt className="text-muted-foreground text-xs">{t(NS, 'detail_channel', 'Canal')}</dt>
                                <dd className="flex items-center gap-1.5">
                                    {isEmail ? (
                                        <Mail className="h-3.5 w-3.5 shrink-0" aria-hidden="true" />
                                    ) : (
                                        <MessageCircle className="h-3.5 w-3.5 shrink-0" aria-hidden="true" />
                                    )}
                                    {send.channelLabel}
                                </dd>
                            </div>
                        )}
                        {language && (
                            <div>
                                <dt className="text-muted-foreground text-xs">{t(NS, 'detail_language', 'Langue')}</dt>
                                <dd>{language}</dd>
                            </div>
                        )}
                    </dl>
                </section>
            </div>

            {body !== '' && (
                <section className="flex flex-col gap-1.5">
                    <div className="flex items-center gap-2">
                        <h3 className="text-muted-foreground text-xs font-medium">
                            {send.status === 'sent' ? t(NS, 'received_title', 'Ce que le voyageur a reçu') : t(NS, 'detail_body', 'Texte préparé')}
                        </h3>
                        <Button type="button" variant="ghost" size="sm" className="ml-auto h-7 px-2 text-xs" onClick={() => onCopy(body)}>
                            <Copy className="h-3.5 w-3.5" aria-hidden="true" />
                            {t(NS, 'copy_text', 'Copier')}
                        </Button>
                    </div>
                    {isEmail ? (
                        <div className="overflow-hidden rounded-md border">
                            {send.subject && (
                                <p className="bg-muted/40 border-b px-3 py-1.5 text-xs">
                                    <span className="text-muted-foreground">{t(NS, 'email_subject_label', 'Objet')} : </span>
                                    {send.subject}
                                </p>
                            )}
                            <p className="px-3 py-2.5 text-sm break-words whitespace-pre-wrap">
                                <MessageText text={body} linkClassName="text-primary" />
                            </p>
                        </div>
                    ) : (
                        // Comme dans la messagerie : la bulle verte d'un message sortant.
                        <div className="flex justify-end">
                            <p className="max-w-[90%] rounded-2xl rounded-br-md bg-[#31b08f] px-3.5 py-2.5 text-sm break-words whitespace-pre-wrap text-white">
                                <MessageText text={body} linkClassName="text-white" />
                            </p>
                        </div>
                    )}
                </section>
            )}

            {(send.reservationUrl || send.inboxUrl) && (
                <div className="flex flex-wrap justify-end gap-2 border-t pt-3">
                    {send.reservationUrl && (
                        <Button asChild variant="outline" size="sm">
                            <Link href={send.reservationUrl}>
                                <CalendarDays className="h-4 w-4" aria-hidden="true" />
                                {t(NS, 'view_reservation', 'Voir la réservation')}
                            </Link>
                        </Button>
                    )}
                    {send.inboxUrl && (
                        <Button asChild variant="outline" size="sm">
                            <Link href={send.inboxUrl}>
                                <MessageCircle className="h-4 w-4" aria-hidden="true" />
                                {t(NS, 'open_conversation', 'Ouvrir la conversation')}
                            </Link>
                        </Button>
                    )}
                </div>
            )}
        </>
    );
}
