import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
import { t } from '@/lib/utils';
import { Head, useForm } from '@inertiajs/react';
import axios, { AxiosError, AxiosInstance } from 'axios';
import { useMemo, useState } from 'react';

import FormInput from '@/Components/FormInput';
import PrimaryButton from '@/Components/PrimaryButton';
import TextInput from '@/Components/TextInput';
import { User } from '@/types';
import {
    KeyRound,
    Loader2,
    QrCode,
    RefreshCcw,
    ShieldCheck,
    ShieldOff,
} from 'lucide-react';
import React from 'react';

type Props = {
    twoFactorEnabled?: boolean;
    auth?: { user: User };
};

type QrResponse = { svg: string; url?: string };

type PendingAction = () => Promise<void>;

function isAxiosError(e: unknown): e is AxiosError {
    return axios.isAxiosError(e);
}

function statusOf(e: unknown): number | null {
    if (!isAxiosError(e)) return null;
    return e.response?.status ?? null;
}

const http: AxiosInstance = axios.create();

http.interceptors.response.use(
    (res) => res,
    (error) => Promise.reject(error),
);

export default function Security({ twoFactorEnabled = false }: Props) {
    const [enabled, setEnabled] = useState<boolean>(twoFactorEnabled);

    const [busy, setBusy] = useState(false);
    const [notice, setNotice] = useState<string | null>(null);
    const [error, setError] = useState<string | null>(null);

    const [qrSvg, setQrSvg] = useState<string | null>(null);
    const [otpauthUrl, setOtpauthUrl] = useState<string | null>(null);
    const [recoveryCodes, setRecoveryCodes] = useState<string[] | null>(null);

    const [pwRequired, setPwRequired] = useState(false);
    const [pendingAction, setPendingAction] = useState<PendingAction | null>(
        null,
    );

    const passwordForm = useForm<{ password: string }>({ password: '' });
    const confirmForm = useForm<{ code: string }>({ code: '' });

    const canConfirm = useMemo(
        () => confirmForm.data.code.trim().length > 0,
        [confirmForm.data.code],
    );

    const showError = (msg: string) => {
        setError(msg);
        setNotice(null);
    };

    const showNotice = (msg: string) => {
        setNotice(msg);
        setError(null);
    };

    const requirePassword = (action: PendingAction) => {
        setPendingAction(() => action);
        setPwRequired(true);
        passwordForm.reset('password');
        passwordForm.clearErrors();
        setError(null);
        setNotice(null);
    };

    const withBusy = async (fn: () => Promise<void>) => {
        setBusy(true);
        try {
            await fn();
        } finally {
            setBusy(false);
        }
    };

    const runAction = async (action: PendingAction, fallbackError: string) => {
        await withBusy(async () => {
            try {
                await action();
            } catch (e) {
                if (statusOf(e) === 423) {
                    requirePassword(action);
                    return;
                }
                showError(fallbackError);
            }
        });
    };

    const fetchQr = async () => {
        const { data } = await http.get<QrResponse>(
            route('two-factor.qr-code'),
        );
        setQrSvg(data.svg);
        setOtpauthUrl(data.url ?? null);
    };

    const loadRecoveryCodes = async () => {
        const { data } = await http.get<string[]>(
            route('two-factor.recovery-codes'),
        );
        setRecoveryCodes(Array.isArray(data) ? data : null);
    };

    // ===== Actions =====

    const enable2FA: PendingAction = async () => {
        await http.post(route('two-factor.enable'));
        setEnabled(true);
        setRecoveryCodes(null);
        showNotice('2FA attivato. Scansiona il QR e conferma con il codice.');
        await fetchQr();
    };

    const confirm2FA: PendingAction = async () => {
        try {
            await http.post(route('two-factor.confirm'), {
                code: confirmForm.data.code,
            });
        } catch (e) {
            // 423 gestito da runAction sopra
            if (statusOf(e) === 422) {
                showError('Il codice di verifica non è valido.');
                return;
            }
            throw e;
        }

        showNotice('2FA confermato con successo.');
        confirmForm.reset('code');
        await loadRecoveryCodes();
    };

    const regenerateRecoveryCodes: PendingAction = async () => {
        await http.post(route('two-factor.regenerate-recovery-codes'));
        showNotice('Recovery codes rigenerati.');
        await loadRecoveryCodes();
    };

    const disable2FA: PendingAction = async () => {
        await http.delete(route('two-factor.disable'));
        setEnabled(false);
        setQrSvg(null);
        setOtpauthUrl(null);
        setRecoveryCodes(null);
        confirmForm.reset('code');
        showNotice('2FA disattivato.');
    };

    // ===== Password confirm flow =====

    const confirmPasswordAndRun = async () => {
        await withBusy(async () => {
            passwordForm.clearErrors();

            try {
                await http.post(route('password.confirm.store'), {
                    password: passwordForm.data.password,
                });
            } catch (e) {
                // qui spesso è 422
                showError('Password non corretta.');
                return;
            }

            setPwRequired(false);

            const action = pendingAction;
            setPendingAction(null);
            if (action) {
                await runAction(action, 'Operazione non riuscita.');
            }
        });
    };

    return (
        <AuthenticatedLayout>
            <Head title={t('Sicurezza')} />

            <div className="mx-auto max-w-3xl px-4 py-10">
                <div className="mb-8">
                    <h1 className="scroll-m-20 text-3xl font-semibold tracking-tight">
                        {t('Sicurezza')}
                    </h1>
                    <p className="mt-2 text-neutral-600">
                        {t(
                            'Gestisci l’autenticazione a due fattori (2FA): attiva, conferma, rigenera o disattiva.',
                        )}
                    </p>
                </div>

                {(notice || error) && (
                    <div
                        className={`mb-6 rounded-xl border p-4 ${
                            error
                                ? 'border-red-200 bg-red-50 text-red-700'
                                : 'border-green-200 bg-green-50 text-green-700'
                        }`}
                    >
                        {error ?? notice}
                    </div>
                )}

                {/* Password confirmation */}
                {pwRequired && (
                    <div className="mb-6 rounded-xl border bg-white p-4">
                        <div className="flex items-center gap-2 font-medium">
                            <KeyRound className="h-4 w-4" />
                            {t('Conferma password')}
                        </div>

                        <p className="mt-2 text-sm text-neutral-600">
                            {t(
                                'Per questa operazione è necessaria la conferma della password.',
                            )}
                        </p>

                        <div className="mt-4">
                            <FormInput
                                label="Password"
                                id="password"
                                error={undefined}
                            >
                                <TextInput
                                    type="password"
                                    value={passwordForm.data.password}
                                    onChange={(
                                        e: React.ChangeEvent<HTMLInputElement>,
                                    ) =>
                                        passwordForm.setData(
                                            'password',
                                            e.target.value,
                                        )
                                    }
                                    required
                                    isFocused
                                />
                            </FormInput>
                        </div>

                        <div className="mt-4 flex gap-3">
                            <PrimaryButton
                                disabled={
                                    busy ||
                                    passwordForm.data.password.length === 0
                                }
                                onClick={() => {
                                    void confirmPasswordAndRun();
                                }}
                            >
                                {busy ? (
                                    <Loader2 className="mr-2 animate-spin" />
                                ) : null}
                                {t('Continua')}
                            </PrimaryButton>

                            <button
                                type="button"
                                className="rounded-lg border px-4 py-2"
                                onClick={() => {
                                    setPwRequired(false);
                                    setPendingAction(null);
                                    passwordForm.reset('password');
                                }}
                                disabled={busy}
                            >
                                {t('Annulla')}
                            </button>
                        </div>
                    </div>
                )}

                <div className="rounded-2xl border bg-white p-6 shadow-sm">
                    <div className="flex items-start justify-between gap-4">
                        <div>
                            <div className="flex items-center gap-2">
                                {enabled ? (
                                    <ShieldCheck className="h-5 w-5" />
                                ) : (
                                    <ShieldOff className="h-5 w-5" />
                                )}
                                <h2 className="text-xl font-semibold">
                                    {t('Autenticazione a due fattori')}
                                </h2>
                            </div>
                            <p className="mt-2 text-sm text-neutral-600">
                                {enabled
                                    ? t('2FA è attivo per il tuo account.')
                                    : t(
                                          '2FA non è attivo. Attivalo per aumentare la sicurezza del tuo account.',
                                      )}
                            </p>
                        </div>

                        {!enabled ? (
                            <PrimaryButton
                                disabled={busy || pwRequired}
                                onClick={() =>
                                    runAction(
                                        enable2FA,
                                        'Impossibile attivare il 2FA.',
                                    )
                                }
                            >
                                {busy ? (
                                    <Loader2 className="mr-2 animate-spin" />
                                ) : null}
                                {t('Attiva 2FA')}
                            </PrimaryButton>
                        ) : (
                            <PrimaryButton
                                disabled={busy || pwRequired}
                                onClick={() =>
                                    runAction(
                                        disable2FA,
                                        'Impossibile disattivare il 2FA.',
                                    )
                                }
                                className="bg-red-600"
                            >
                                {busy ? (
                                    <Loader2 className="mr-2 animate-spin" />
                                ) : null}
                                {t('Disattiva')}
                            </PrimaryButton>
                        )}
                    </div>

                    {/* QR / Confirm */}
                    {enabled && (
                        <div className="mt-8 border-t pt-6">
                            <div className="flex items-center justify-between gap-4">
                                <div className="flex items-center gap-2 font-medium">
                                    <QrCode className="h-4 w-4" />
                                    {t('QR e conferma')}
                                </div>

                                <button
                                    type="button"
                                    className="rounded-lg border px-4 py-2"
                                    disabled={busy || pwRequired}
                                    onClick={() =>
                                        runAction(
                                            fetchQr,
                                            'Impossibile recuperare il QR.',
                                        )
                                    }
                                >
                                    {t('Mostra QR')}
                                </button>
                            </div>

                            {qrSvg && (
                                <div className="mt-6 grid gap-6 md:grid-cols-2">
                                    <div className="rounded-xl border p-4">
                                        <div
                                            className="flex justify-center"
                                            dangerouslySetInnerHTML={{
                                                __html: qrSvg,
                                            }}
                                        />
                                        {otpauthUrl ? (
                                            <p className="mt-3 break-all text-xs text-neutral-500">
                                                {t('otpauth:')} {otpauthUrl}
                                            </p>
                                        ) : null}
                                    </div>

                                    <div className="rounded-xl border p-4">
                                        <p className="text-sm text-neutral-600">
                                            {t(
                                                'Inserisci il codice a 6 cifre generato dalla tua app per confermare l’attivazione.',
                                            )}
                                        </p>

                                        <div className="mt-4">
                                            <FormInput
                                                label="Codice di verifica"
                                                id="code"
                                                error={undefined}
                                            >
                                                <TextInput
                                                    value={
                                                        confirmForm.data.code
                                                    }
                                                    onChange={(
                                                        e: React.ChangeEvent<HTMLInputElement>,
                                                    ) =>
                                                        confirmForm.setData(
                                                            'code',
                                                            e.target.value,
                                                        )
                                                    }
                                                    required
                                                    isFocused={false}
                                                />
                                            </FormInput>
                                        </div>

                                        <div className="mt-4">
                                            <PrimaryButton
                                                disabled={
                                                    busy ||
                                                    pwRequired ||
                                                    !canConfirm
                                                }
                                                onClick={() =>
                                                    runAction(
                                                        confirm2FA,
                                                        'Impossibile confermare il 2FA.',
                                                    )
                                                }
                                            >
                                                {busy ? (
                                                    <Loader2 className="mr-2 animate-spin" />
                                                ) : null}
                                                {t('Conferma')}
                                            </PrimaryButton>
                                        </div>
                                    </div>
                                </div>
                            )}
                        </div>
                    )}

                    {/* Recovery codes */}
                    {enabled && (
                        <div className="mt-8 border-t pt-6">
                            <div className="flex items-center justify-between gap-4">
                                <div className="flex items-center gap-2 font-medium">
                                    <RefreshCcw className="h-4 w-4" />
                                    {t('Recovery codes')}
                                </div>

                                <div className="flex gap-2">
                                    <button
                                        type="button"
                                        className="rounded-lg border px-4 py-2"
                                        disabled={busy || pwRequired}
                                        onClick={() =>
                                            runAction(
                                                loadRecoveryCodes,
                                                'Impossibile recuperare i recovery codes.',
                                            )
                                        }
                                    >
                                        {t('Mostra')}
                                    </button>

                                    <button
                                        type="button"
                                        className="rounded-lg border px-4 py-2"
                                        disabled={busy || pwRequired}
                                        onClick={() =>
                                            runAction(
                                                regenerateRecoveryCodes,
                                                'Impossibile rigenerare i recovery codes.',
                                            )
                                        }
                                    >
                                        {t('Rigenera')}
                                    </button>
                                </div>
                            </div>

                            {recoveryCodes && (
                                <div className="mt-4 rounded-xl border bg-neutral-50 p-4">
                                    <p className="text-sm text-neutral-600">
                                        {t(
                                            'Conserva questi codici in un posto sicuro. Ogni codice può essere usato una sola volta.',
                                        )}
                                    </p>

                                    <ul className="mt-3 grid gap-2 sm:grid-cols-2">
                                        {recoveryCodes.map((c) => (
                                            <li
                                                key={c}
                                                className="rounded-lg border bg-white px-3 py-2 font-mono text-sm"
                                            >
                                                {c}
                                            </li>
                                        ))}
                                    </ul>
                                </div>
                            )}
                        </div>
                    )}
                </div>
            </div>
        </AuthenticatedLayout>
    );
}
