import { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import { Toaster, toast, type Toast } from 'react-hot-toast';

import { toastIconClassNames, toastLoadingSpinnerClassName, toastMessageClassName, toastShellClassName } from '@admin/components/ui/field-styles';
import { cn } from '@admin/lib/utils';

export type AdminToastVariant = keyof typeof toastIconClassNames | 'loading';

type AdminToastBarProps = {
    t: Toast;
    variant: AdminToastVariant;
    message: string;
};

function AdminToastBar({ t, variant, message }: AdminToastBarProps) {
    return (
        <div
            className={cn(
                toastShellClassName,
                'w-full max-w-sm transition-all duration-300',
                t.visible ? 'opacity-100 translate-y-0' : 'opacity-0 -translate-y-1',
            )}
            role="alert"
        >
            <div className="flex p-4">
                <div className="flex-shrink-0">
                    {variant === 'loading' ? (
                        <div className={toastLoadingSpinnerClassName} role="status" aria-label="Loading">
                            <span className="sr-only">Loading...</span>
                        </div>
                    ) : (
                        <i className={cn(toastIconClassNames[variant], 'text-base leading-none mt-0.5')} aria-hidden />
                    )}
                </div>
                <div className="ms-3 flex-1 min-w-0">
                    <p className={toastMessageClassName}>{message}</p>
                </div>
                {variant !== 'loading' && (
                    <button
                        type="button"
                        className="ms-3 flex-shrink-0 text-gray-400 hover:text-gray-600 dark:text-white/50 dark:hover:text-white/80"
                        onClick={() => toast.dismiss(t.id)}
                        aria-label="Dismiss"
                    >
                        <i className="ri-close-line text-base" />
                    </button>
                )}
            </div>
        </div>
    );
}

const toastDuration: Record<Exclude<AdminToastVariant, 'loading'>, number> = {
    success: 4000,
    error: 6000,
    warning: 5000,
    info: 4000,
};

function showToast(variant: AdminToastVariant, message: string, id?: string): string {
    return toast.custom((t) => <AdminToastBar t={t} variant={variant} message={message} />, {
        id,
        duration: variant === 'loading' ? Infinity : toastDuration[variant],
        position: 'top-right',
    });
}

export const adminToast = {
    loading: (message: string) => showToast('loading', message),
    success: (message: string, id?: string) => showToast('success', message, id),
    error: (message: string, id?: string) => showToast('error', message, id),
    warning: (message: string, id?: string) => showToast('warning', message, id),
    info: (message: string, id?: string) => showToast('info', message, id),
    promise<T>(
        promise: Promise<T>,
        messages: {
            loading: string;
            success: string | ((value: T) => string);
            error: string | ((error: unknown) => string);
        },
    ): Promise<T> {
        const id = adminToast.loading(messages.loading);

        return promise
            .then((value) => {
                const successMessage = typeof messages.success === 'function' ? messages.success(value) : messages.success;
                adminToast.success(successMessage, id);

                return value;
            })
            .catch((error: unknown) => {
                const errorMessage = typeof messages.error === 'function' ? messages.error(error) : messages.error;
                adminToast.error(errorMessage, id);
                throw error;
            });
    },
};

/** Mount once in admin `app.tsx` — Synto basic toasts, top-right, portaled to body. */
export function AdminToaster() {
    const [mounted, setMounted] = useState(false);

    useEffect(() => {
        setMounted(true);
    }, []);

    if (!mounted) {
        return null;
    }

    return createPortal(
        <Toaster
            position="top-right"
            containerStyle={{ zIndex: 99999 }}
            gutter={12}
            toastOptions={{
                className: 'admin-toast-host',
                position: 'top-right',
            }}
        />,
        document.body,
    );
}
