import { getReflection, getAccess, setRefresh, getHeaders, tryCompress, ALG } from '/assets/{{ version }}/js/core.js';

async function hash(
    app_name,
    account,
    password,
) {
    const encoder = new TextEncoder();

    const encoded_app_name = encoder.encode(app_name);
    const encoded_account = encoder.encode(account);
    const encoded_password = encoder.encode(password);

    const all = new Uint8Array([...encoded_app_name, ...encoded_account, ...encoded_password]);

    const reflection = await getReflection();

    const alg = ALG[reflection.auth.password.client_hash]
    const hash = await crypto.subtle.digest(alg, all);

    return new Uint8Array(hash)
}

export async function register(
    account,
    password,
    app_name,
) {
    await __wbg_init();

    const password_hash = await hash(app_name, account, password);
    const start_req = registration_start_req(account, password_hash);

    const start_res = await fetch('/registration_start', {
        method: 'PUT',
        body: start_req.request,
        headers: getHeaders({ cookies: false }),
    });
    const server_message = await start_res.bytes();

    const finish_req = registration_finish_req(
        account, password_hash, start_req.client_state, server_message
    );

    const finish_res = await fetch('/registration_finish', {
        method: 'PUT',
        body: finish_req.request,
        headers: getHeaders({ cookies: false }),
    });
    const encrypted_totp_mfa = await finish_res.bytes();

    const mfa_qr_code = decrypt_totp_mfa(encrypted_totp_mfa, finish_req.private_key, app_name, account);

    return mfa_qr_code;
}

export async function login(
    account,
    password,
    mfa_code,
    app_name,
    get_cookies,
) {
    await __wbg_init();

    const password_hash = await hash(app_name, account, password);
    const start_req = login_start_req(account, password_hash);

    const start_res = await fetch('/login_start', {
        method: 'PUT',
        body: start_req.request,
        headers: getHeaders({ cookies: false }),
    });
    const server_message = await start_res.bytes();

    const finish_req = login_finish_req(
        account, password_hash, mfa_code, start_req.client_state, server_message
    );

    const finish_res = await fetch('/login_finish', {
        method: 'PUT',
        body: finish_req.request,
        credentials: get_cookies ? 'include' : 'omit',
        headers: getHeaders({ cookies: false }),
    });
    const encrypted_token = await finish_res.bytes();

    const refresh_token = decrypt_token(encrypted_token, finish_req.session_key);

    await setRefresh(refresh_token);
}

export async function invoke(actionId, payload) {
    await __wbg_init();

    const reflection = await getReflection();

    for (let i = 0; i < reflection.actions.length; i += 1) {
        const action = reflection.actions[i];

        if ((action.name == actionId || action.idx == actionId) && action.triggered_by.includes("Ordinary")) {
            const req = invoke_req(
                action.idx,
                JSON.stringify(payload),
                JSON.stringify(action.accepts),
                action.protected ? await getAccess(false) : new Uint8Array(),
            );

            const send = await tryCompress(req, 'application/octet-stream');

            const res = await fetch('/invoke', {
                method: 'PUT',
                body: send.body,
                headers: {
                    ...getHeaders({ cookies: false }),
                    ...send.headers,
                },
            });

            const res_bytes = await res.bytes();

            const res_json = invoke_res(JSON.stringify(action.returns), res_bytes);
            return JSON.parse(res_json);
        }
    }
}
