import {fetch_timeout} from "./util";
import {API_ROOT} from "./config";
import {Logger, logSetup} from "./logger";
import {getCookie, setCookie} from "./cookie";
import {browser} from "$app/environment";

logSetup();
const logger = new Logger("auth.ts");

export function redact_token(token: string) {
    const stars = "*".repeat(token.length - 5);
    return token.substring(0, 5) + stars;
}

export interface UserInfo {
    data: UserData,
    metadata: object
}

export interface UserData {
    actorType: string,
    actor: Actor
}

export interface Actor {
    id: string,
    organizationID: string,
    email: string,
    createdAt: string,
    hasTOTPAuthenticator: string
}

export async function get_user_info(api_key: string): Promise<UserInfo | string> {
    logger.info("Asking server for user information");
    try {
        const resp = await fetch_timeout(`${API_ROOT}/v2/whoami`, {
            'method': 'GET',
            'headers': {
                'Authorization': `Bearer ${api_key}`
            }
        });
        if (!resp.ok) {
            const rawerror = JSON.parse(await resp.text()).errors[0].message;
            logger.error(`error fetching user information: ${rawerror}`);
            return rawerror;
        }
        return JSON.parse(await resp.text()) as UserInfo;
    } catch (e) {
        logger.error(`Error fetching userinfo: ${e}`);
        return `${e}`
    }
}

export async function enforce_session(): Promise<[boolean, string]> {
    logger.info("Checking session authentication");
    const session_token = getCookie("sessionToken");
    if (session_token === "") {
        logger.error("No session token is present");
        setCookie("sessionToken", "", -1);
        return [false, ""];
    }
    logger.info(`Session token is ${redact_token(session_token)}`);

    try {
        const resp = await fetch_timeout(`${API_ROOT}/v1/auth/check_session`, {
            'method': 'POST',
            'headers': {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${session_token}`
            }
        });
        if (!resp.ok) {
            const rawerror = JSON.parse(await resp.text()).errors[0].message;
            logger.error(`session token is invalid: ${rawerror}`);
            setCookie("sessionToken", "", -1);
            return [false, rawerror];
        } else {
            logger.info("session token OK");
            // session ok
            return [true, session_token];
        }
    } catch (e) {
        // error in http request
        logger.error(`session token is invalid: ${e}`);
        setCookie("sessionToken", "", -1);
        return [false, `${e}`]
    }
}

export async function enforce_auth(): Promise<[boolean, string]> {
    logger.info("Checking mfa authentication");

    const session_result = await enforce_session();

    if (!session_result[0]) {
        // session token is invalid
        logger.error("Session token is invalid, therefore auth token cannot be valid");
        return [false, session_result[1]];
    }

    const session_token = session_result[1];

    const auth_token = getCookie("authToken");
    if (auth_token === "") {
        logger.error("No auth token is present");
        setCookie("authToken", "", -1);
        return [false, ""];
    }
    logger.info(`MFA token is ${redact_token(auth_token)}`);

    try {
        const resp = await fetch_timeout(`${API_ROOT}/v1/auth/check_auth`, {
            'method': 'POST',
            'headers': {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${session_token} ${auth_token}`
            }
        });
        if (!resp.ok) {
            const rawerror = JSON.parse(await resp.text()).errors[0].message;
            setCookie("authToken", "", -1);
            return [false, rawerror];
        } else {
            // session ok
            logger.info("MFA token is OK");
            if (browser) {
                document.documentElement.classList.add("loggedin");
            }
            return [true, `${session_token} ${auth_token}`];
        }
    } catch (e) {
        // error in http request
        setCookie("authToken", "", -1);
        return [false, `${e}`]
    }
}

export function renderDevMenu() {
    if (!browser) return false;
    if (localStorage.getItem("allowdev") === "HACKERMAN") {
        console.log("allowing dev menu");
        return true;
    }
    console.log("not allowing dev menu");
    return false;
}