import React, {useEffect, useState} from 'react';
import axios from 'axios';
import {usePage} from '@inertiajs/react';
import MainLayout from '@/layouts/MainLayout';
import AppPageHeader from '@/components/AppPageHeader';

type Status = 'disabled' | 'confirming' | 'enabled';
export default function Security(): JSX.Element {
    const {twoFactor} = usePage<{ twoFactor?: { enabled: boolean; confirmed: boolean } }>().props;
    const [status, setStatus] = useState<Status>(() => twoFactor?.enabled ? (twoFactor.confirmed ? 'enabled' : 'confirming') : 'disabled');
    const [qrCode, setQrCode] = useState('');
    const [secretKey, setSecretKey] = useState('');
    const [recoveryCodes, setRecoveryCodes] = useState<string[]>([]);
    const [code, setCode] = useState('');
    const [busy, setBusy] = useState(false);
    const [error, setError] = useState('');

    const loadDetails = async () => {
        const [qr, secret, recovery] = await Promise.all([
            axios.get('/user/two-factor-qr-code'),
            axios.get('/user/two-factor-secret-key'),
            axios.get('/user/two-factor-recovery-codes'),
        ]);
        setQrCode(qr.data.svg ?? '');
        setSecretKey(secret.data.secretKey ?? '');
        setRecoveryCodes(recovery.data ?? []);
    };

    useEffect(() => {
        if (status === 'disabled') return;

        loadDetails().catch(() => setError('Unable to load two-factor authentication details.'));
    }, []);

    const enable = async () => {
        setBusy(true);
        setError('');
        try {
            await axios.post('/user/two-factor-authentication');
            await loadDetails();
            setStatus('confirming');
        } catch {
            setError('Unable to enable two-factor authentication.');
        } finally {
            setBusy(false);
        }
    };

    const confirm = async () => {
        setBusy(true);
        setError('');
        try {
            await axios.post('/user/confirmed-two-factor-authentication', {code});
            setStatus('enabled');
            setCode('');
            await loadDetails();
        } catch {
            setError('The authentication code was not accepted.');
        } finally {
            setBusy(false);
        }
    };

    const disable = async () => {
        setBusy(true);
        setError('');
        try {
            await axios.delete('/user/two-factor-authentication');
            setStatus('disabled');
            setQrCode('');
            setSecretKey('');
            setRecoveryCodes([]);
        } catch {
            setError('Unable to disable two-factor authentication.');
        } finally {
            setBusy(false);
        }
    };

    const regenerateRecoveryCodes = async () => {
        setBusy(true);
        setError('');
        try {
            await axios.post('/user/two-factor-recovery-codes', {}, {headers: {Accept: 'application/json'}});
            const response = await axios.get('/user/two-factor-recovery-codes');
            setRecoveryCodes(response.data ?? []);
        } catch {
            setError('Unable to regenerate recovery codes.');
        } finally {
            setBusy(false);
        }
    };

    return (
        <MainLayout hideSidebar>
            <AppPageHeader title="Security" subtitle="Account" showBackButton />

            <section className="max-w-3xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900">
                <div className="border-b border-gray-200 p-5 dark:border-gray-800">
                    <h2 className="text-base font-semibold text-gray-900 dark:text-white">Two-factor authentication</h2>
                    <p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
                        Protect this account with an authenticator app and recovery codes.
                    </p>
                </div>

                <div className="space-y-5 p-5">
                    {error ? <p className="text-sm text-rose-600">{error}</p> : null}

                    {status === 'disabled' ? (
                        <button type="button" className="ti-btn ti-btn-primary" onClick={enable} disabled={busy}>
                            {busy ? 'Enabling...' : 'Enable two-factor authentication'}
                        </button>
                    ) : (
                        <>
                            {qrCode ? <div className="w-fit border border-gray-200 bg-white p-3" dangerouslySetInnerHTML={{__html: qrCode}} /> : null}
                            <p className="text-sm text-gray-600 dark:text-gray-300">Setup key: <code>{secretKey}</code></p>

                            {status === 'confirming' ? (
                                <div className="flex max-w-sm gap-2">
                                    <input
                                        className="ti-form-input"
                                        inputMode="numeric"
                                        placeholder="Authentication code"
                                        value={code}
                                        onChange={event => setCode(event.target.value)}
                                    />
                                    <button type="button" className="ti-btn ti-btn-primary" onClick={confirm} disabled={busy || !code}>
                                        Confirm
                                    </button>
                                </div>
                            ) : (
                                <div className="flex flex-wrap gap-2">
                                    <button type="button" className="ti-btn ti-btn-soft-secondary" onClick={regenerateRecoveryCodes} disabled={busy}>
                                        Regenerate recovery codes
                                    </button>
                                    <button type="button" className="ti-btn ti-btn-soft-danger" onClick={disable} disabled={busy}>
                                        Disable
                                    </button>
                                </div>
                            )}

                            {recoveryCodes.length > 0 ? (
                                <div className="border border-amber-200 bg-amber-50 p-4 text-sm text-amber-950 dark:border-amber-900 dark:bg-amber-950/30 dark:text-amber-100">
                                    <p className="font-medium">Recovery codes</p>
                                    <div className="mt-2 grid grid-cols-1 gap-1 font-mono sm:grid-cols-2">
                                        {recoveryCodes.map(recoveryCode => <span key={recoveryCode}>{recoveryCode}</span>)}
                                    </div>
                                </div>
                            ) : null}
                        </>
                    )}
                </div>
            </section>
        </MainLayout>
    );
}
