/**
 * The assistant endpoints answer with JSON instead of an Inertia response, so they are called
 * with fetch rather than the Inertia router. Laravel's session cookie authenticates the call and
 * the XSRF-TOKEN cookie carries CSRF protection.
 */

function xsrfToken(): string {
    const match = document.cookie.match(/(?:^|;\s*)XSRF-TOKEN=([^;]*)/);

    return match ? decodeURIComponent(match[1]) : '';
}

type ErrorBody = {
    message?: string;
    errors?: Record<string, string[]>;
};

function firstError(body: ErrorBody | null, fallback: string): string {
    const fromErrors = body?.errors
        ? Object.values(body.errors).flat()[0]
        : undefined;

    return fromErrors ?? body?.message ?? fallback;
}

export async function postJson<T>(url: string, body: unknown): Promise<T> {
    const response = await fetch(url, {
        method: 'POST',
        credentials: 'same-origin',
        headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
            'X-Requested-With': 'XMLHttpRequest',
            'X-XSRF-TOKEN': xsrfToken(),
        },
        body: JSON.stringify(body),
    });

    const data: unknown = await response.json().catch(() => null);

    if (!response.ok) {
        throw new Error(
            firstError(
                data as ErrorBody | null,
                "L'assistente non è riuscito a rispondere. Riprova tra poco.",
            ),
        );
    }

    return data as T;
}

/**
 * Turns the validation errors of a bulk endpoint (`rows.2.fiscal_code`, `meetings.0.title`, ...)
 * into messages that name the row, so the preview table says which line to correct.
 */
export function rowErrorMessages(
    errors: Record<string, string>,
    prefix: string,
): string[] {
    return Object.entries(errors).map(([key, message]) => {
        const match = key.match(new RegExp(`^${prefix}\\.(\\d+)\\.`));

        return match ? `Riga ${Number(match[1]) + 1}: ${message}` : message;
    });
}
