import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { useCopyToClipboard } from '@/hooks/use-copy-to-clipboard';
import { useTranslation } from '@/hooks/use-translation';
import type { LogementShowEntryInstructions, LogementShowEntryLink } from '@/types/logement-show';
import { router } from '@inertiajs/react';
import { Check, Copy, Link2, Loader2 } from 'lucide-react';
import { useEffect, useState } from 'react';
import { toast } from 'sonner';
import { NS, fill } from '../format';
import { CardEditLink, SectionTitle } from './detail-card';
import { MissingInstructionsNotice } from './today-card';

/** Libellés des rubriques : ceux de la page publique du voyageur (namespace `instructions`). */
const FIELD_LABELS: Record<string, { key: string; fallback: string }> = {
    maps_url: { key: 'open_maps', fallback: "Voir l'itinéraire" },
    lockbox_code: { key: 'lockbox_code', fallback: 'Code boîtier' },
    residence_code: { key: 'residence_code', fallback: 'Code résidence' },
    floor: { key: 'floor', fallback: 'Étage' },
    apartment_number: { key: 'apartment_number', fallback: 'Appartement' },
    wifi: { key: 'wifi_section', fallback: 'WiFi' },
    notes: { key: 'notes_section', fallback: 'Notes' },
    media: { key: 'media_section', fallback: 'Photos et vidéos' },
};

interface Props {
    instructions: LogementShowEntryInstructions;
    /** Lien d'une heure, présent après un clic sur « Générer » (prop facultative). */
    link: LogementShowEntryLink | null | undefined;
    /** Étape « Instructions d'entrée » de l'assistant ; null sans droit de modification. */
    editHref: string | null;
}

/**
 * Instructions d'entrée du logement. Sans réservation à qui envoyer le lien de
 * son séjour, « Générer un lien » crée un lien public valable UNE heure (créé
 * au clic : l'heure court à partir de là), signé comme celui d'un séjour. Le
 * résumé ne montre que les rubriques remplies, jamais les codes.
 */
export function EntryInstructionsCard({ instructions, link, editHref }: Props) {
    const { t } = useTranslation();
    const [generating, setGenerating] = useState(false);
    const { copiedKey, copy: copyText } = useCopyToClipboard();
    const copied = copiedKey !== null;
    const [now, setNow] = useState(() => Date.now());

    // L'échéance s'affiche « expiré » d'elle-même, sans recharger la page.
    useEffect(() => {
        if (!link) {
            return;
        }
        const timer = window.setInterval(() => setNow(Date.now()), 30_000);
        return () => window.clearInterval(timer);
    }, [link]);

    const copy = async (url: string) => {
        const ok = await copyText(url);
        if (ok) {
            toast.success(t(NS, 'entry_link_copied'));
        }
        return ok;
    };

    const generate = () => {
        setGenerating(true);
        router.reload({
            only: ['entry_link'],
            onSuccess: async (page) => {
                const fresh = page.props.entry_link as LogementShowEntryLink | null | undefined;
                setNow(Date.now());
                if (!fresh) {
                    toast.error(t(NS, 'load_failed'));
                    return;
                }
                // Après l'aller-retour, le navigateur peut refuser la copie : le lien
                // reste affiché avec son propre bouton « Copier ».
                if (!(await copy(fresh.url))) {
                    toast.info(t(NS, 'entry_link_ready'));
                }
            },
            onError: () => toast.error(t(NS, 'load_failed')),
            onFinish: () => setGenerating(false),
        });
    };

    const hasInstructions = instructions.filled.length > 0;
    const expired = link ? new Date(link.expires_at_iso).getTime() <= now : false;

    return (
        <Card data-tour="logement-show-instructions" className="gap-0">
            <CardContent>
                <div className="mb-2 flex items-center justify-between gap-2">
                    <SectionTitle>{t(NS, 'entry_title')}</SectionTitle>
                    {editHref && <CardEditLink href={editHref} label={t(NS, 'edit')} />}
                </div>
                {!hasInstructions ? (
                    <MissingInstructionsNotice addHref={editHref} />
                ) : (
                    <div className="flex flex-col gap-3">
                        <ul className="flex flex-wrap gap-1.5" aria-label={t(NS, 'entry_filled')}>
                            {instructions.filled.map((key) => {
                                const label = FIELD_LABELS[key];
                                return (
                                    <li key={key} className="bg-muted text-muted-foreground rounded-full px-2 py-0.5 text-xs">
                                        {label ? t('instructions', label.key, label.fallback) : key}
                                    </li>
                                );
                            })}
                        </ul>

                        <Button type="button" variant="outline" size="sm" onClick={generate} disabled={generating} className="w-fit gap-1.5">
                            {generating ? (
                                <Loader2 className="h-3.5 w-3.5 animate-spin" aria-hidden="true" />
                            ) : (
                                <Link2 className="h-3.5 w-3.5" aria-hidden="true" />
                            )}
                            {t(NS, link ? 'entry_link_regenerate' : 'entry_link_generate')}
                        </Button>

                        {link && (
                            <div className="flex flex-col gap-1.5">
                                <div className="flex items-center gap-2">
                                    <input
                                        readOnly
                                        value={link.url}
                                        aria-label={t(NS, 'entry_title')}
                                        onFocus={(event) => event.currentTarget.select()}
                                        className="border-input bg-muted/40 text-muted-foreground min-w-0 flex-1 rounded-md border px-2 py-1 font-mono text-xs"
                                    />
                                    <Button
                                        type="button"
                                        variant="outline"
                                        size="sm"
                                        onClick={() => copy(link.url)}
                                        disabled={expired}
                                        className="h-7 gap-1.5 px-2 text-xs"
                                    >
                                        {copied ? (
                                            <Check className="h-3.5 w-3.5" aria-hidden="true" />
                                        ) : (
                                            <Copy className="h-3.5 w-3.5" aria-hidden="true" />
                                        )}
                                        {t(NS, 'entry_link_copy')}
                                    </Button>
                                </div>
                                <p className={expired ? 'text-xs font-medium text-amber-700 dark:text-amber-300' : 'text-muted-foreground text-xs'}>
                                    {expired ? t(NS, 'entry_link_expired') : fill(t(NS, 'entry_link_valid_until'), { time: link.expires_at })}
                                </p>
                            </div>
                        )}

                        <p className="text-muted-foreground text-xs">{t(NS, 'entry_link_hint')}</p>
                    </div>
                )}
            </CardContent>
        </Card>
    );
}
