import { FC, ReactNode, useCallback, useEffect, useRef, useState } from 'react';
import { createPortal } from "react-dom";

export type UseInvoicePreviewOptions<T> = {
    persistKey?: string;          // clave para guardar el pin en localStorage
    pinnedWidthClass?: string;    // ancho al anclar (Tailwind), p.ej. "w-[500px]"
    onOpenChange?: (open: boolean) => void; // callback opcional
};

export type InvoicePreviewHook<T> = {
    isOpen: boolean;
    isPinned: boolean;
    item: T | null;
    open: (item: T) => void;
    close: () => void;
    togglePin: () => void;

    /** Añade margen derecho al listado si está anclado */
    containerClassName: string;

    /** Renderiza el preview en un portal (body). Debes pasar tu Card como children render-prop */
    PreviewPortal: FC<{
        children: (p: {
            item: T;
            isOpen: boolean;
            isPinned: boolean;
            onClose: () => void;
            onTogglePin: () => void;
        }) => ReactNode
    }>;
};

export function useInvoicePreview<T = unknown>(
    opts?: UseInvoicePreviewOptions<T>
): InvoicePreviewHook<T> {
    const { persistKey = "invoice-preview-pin", pinnedWidthClass = "w-[500px]", onOpenChange } = opts ?? {};
    const [isOpen, setOpen] = useState(false);
    const [item, setItem] = useState<T | null>(null);
    const [isPinned, setPinned] = useState<boolean>(() => {
        try { return localStorage.getItem(persistKey) === "1"; } catch { return false; }
    });

    // Guardar y restaurar foco al cerrar (mejor accesibilidad)
    const lastFocusedRef = useRef<HTMLElement | null>(null);
    const rememberFocus = () => { lastFocusedRef.current = (document.activeElement as HTMLElement) ?? null; };
    const restoreFocus = () => { lastFocusedRef.current?.focus?.(); };

    const open = useCallback((next: T) => {
        rememberFocus();
        setItem(next);
        setOpen(true);
        onOpenChange?.(true);
    }, [onOpenChange]);

    const close = useCallback(() => {
        if (isPinned) return; // anclado no se cierra
        setOpen(false);
        onOpenChange?.(false);
        setTimeout(restoreFocus, 0);
    }, [isPinned, onOpenChange]);

    const togglePin = useCallback(() => {
        setPinned((prev) => {
            const next = !prev;
            try { localStorage.setItem(persistKey, next ? "1" : "0"); } catch { }
            return next;
        });
    }, [persistKey]);

    // Bloqueo de scroll cuando está abierto y NO anclado
    useEffect(() => {
        if (isOpen && !isPinned) {
            const prev = document.body.style.overflow;
            document.body.style.overflow = "hidden";
            return () => { document.body.style.overflow = prev; };
        }
    }, [isOpen, isPinned]);

    // Cerrar con ESC (solo si no está anclado)
    useEffect(() => {
        if (!isOpen || isPinned) return;
        const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") close(); };
        window.addEventListener("keydown", onKey);
        return () => window.removeEventListener("keydown", onKey);
    }, [isOpen, isPinned, close]);

    const containerClassName = isPinned ? `mr-[--preview-width] [--preview-width:theme(spacing.0)] ${pinnedWidthClass ? "" : ""}` : "";
    // Nota: preferimos aplicar el margen directamente en el layout (ver uso abajo)

    const PreviewPortal: InvoicePreviewHook<T>["PreviewPortal"] = useCallback(({ children }) => {
        if (!item) return null;
        const node = children({
            item,
            isOpen,
            isPinned,
            onClose: close,
            onTogglePin: togglePin,
        });
        return createPortal(node as ReactNode, document.body);
    }, [item, isOpen, isPinned, close, togglePin]);

    return { isOpen, isPinned, item, open, close, togglePin, containerClassName, PreviewPortal };
}
