/**
 * Tente une connexion en une requête JSON dédiée (sans redirection Inertia).
 *
 * On sait ainsi AVANT toute navigation si les identifiants sont valides :
 *   - `ok: true`             → e-mail + mot de passe corrects, session ouverte.
 *   - `ok: true, twoFactor`  → identifiants corrects mais 2FA requise.
 *   - `ok: false, errors`    → identifiants invalides (ou trop de tentatives).
 *
 * Fortify renvoie du JSON dès que l'en-tête `Accept: application/json` est
 * présent : 204 en cas de succès, 422 en cas d'échec de validation.
 */
export type LoginOutcome =
    | { ok: true; twoFactor: boolean }
    | { ok: false; errors: Record<string, string> };

function readCookie(name: string): string | null {
    const row = document.cookie
        .split('; ')
        .find((entry) => entry.startsWith(name + '='));

    return row ? decodeURIComponent(row.slice(name.length + 1)) : null;
}

function flattenErrors(bag: unknown): Record<string, string> {
    const errors: Record<string, string> = {};

    if (bag && typeof bag === 'object') {
        for (const [key, value] of Object.entries(bag as Record<string, unknown>)) {
            errors[key] = Array.isArray(value) ? String(value[0]) : String(value);
        }
    }

    return errors;
}

export async function attemptLogin(
    payload: Record<string, unknown>,
): Promise<LoginOutcome> {
    const xsrf = readCookie('XSRF-TOKEN');

    let response: Response;

    try {
        response = await fetch('/login', {
            method: 'POST',
            credentials: 'same-origin',
            headers: {
                'Content-Type': 'application/json',
                Accept: 'application/json',
                'X-Requested-With': 'XMLHttpRequest',
                ...(xsrf ? { 'X-XSRF-TOKEN': xsrf } : {}),
            },
            body: JSON.stringify(payload),
        });
    } catch {
        return { ok: false, errors: { email: 'Connexion au serveur impossible.' } };
    }

    if (response.ok) {
        let twoFactor = false;

        try {
            const data = await response.json();
            twoFactor = data?.two_factor === true;
        } catch {
            /* 204 sans corps : connexion simple réussie. */
        }

        return { ok: true, twoFactor };
    }

    if (response.status === 422 || response.status === 429) {
        let data: { errors?: unknown; message?: string } = {};

        try {
            data = await response.json();
        } catch {
            /* corps illisible */
        }

        let errors = flattenErrors(data.errors);

        if (!Object.keys(errors).length) {
            errors = { email: data.message ?? 'Identifiants invalides.' };
        }

        return { ok: false, errors };
    }

    if (response.status === 419) {
        return {
            ok: false,
            errors: { email: 'Session expirée, rechargez la page.' },
        };
    }

    return { ok: false, errors: { email: 'Une erreur est survenue.' } };
}
