var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { useQuery } from '@tanstack/react-query';
import { z } from 'zod/v4';
import { HTTP_METHOD, RequestError, validateResponse } from '@darajs/ui-utils';
import { request } from '../api/http';
import { useRequestExtras } from '../shared/context/request-extras-context';
import {} from '../types';
import { notifySessionLoggedOut, setSessionIdentifier } from './session-state';
var AuthenticationErrorReason;
(function (AuthenticationErrorReason) {
    AuthenticationErrorReason["BAD_REQUEST"] = "bad_request";
    AuthenticationErrorReason["EXPIRED_TOKEN"] = "expired";
    AuthenticationErrorReason["INVALID_CREDENTIALS"] = "invalid_credentials";
    AuthenticationErrorReason["INVALID_TOKEN"] = "invalid_token";
    AuthenticationErrorReason["OTHER"] = "other";
    AuthenticationErrorReason["UNAUTHORIZED"] = "unauthorized";
})(AuthenticationErrorReason || (AuthenticationErrorReason = {}));
const AuthenticationErrorSchema = z.object({
    message: z.string(),
    reason: z.enum([
        AuthenticationErrorReason.BAD_REQUEST,
        AuthenticationErrorReason.EXPIRED_TOKEN,
        AuthenticationErrorReason.INVALID_CREDENTIALS,
        AuthenticationErrorReason.INVALID_TOKEN,
        AuthenticationErrorReason.OTHER,
        AuthenticationErrorReason.UNAUTHORIZED,
    ]),
});
/**
 * Whether a message is an authentication error
 *
 * @param message message
 */
function parseAuthenticationError(message) {
    const parsed = AuthenticationErrorSchema.safeParse(message);
    if (!parsed.success) {
        return null;
    }
    return parsed.data;
}
/**
 * Whether the error should be ignored
 *
 * @param message error message
 * @param ignoreErrors error types to ignore
 */
function shouldIgnoreError(message, ignoreErrors) {
    return ignoreErrors && ignoreErrors.includes(message.reason);
}
/**
 * Returns true if the error should redirect to login, otherwise it should redirect to the error page
 *
 * @param message error message
 */
function shouldRedirectToLogin(message) {
    return [
        AuthenticationErrorReason.INVALID_CREDENTIALS,
        AuthenticationErrorReason.EXPIRED_TOKEN,
        AuthenticationErrorReason.INVALID_TOKEN,
    ].includes(message.reason);
}
/**
 * Revoke the current session
 */
export function revokeSession() {
    return __awaiter(this, void 0, void 0, function* () {
        try {
            const response = yield request('/api/auth/revoke-session', {
                method: HTTP_METHOD.POST,
            });
            if (response.ok) {
                const responseData = yield response.json();
                return responseData;
            }
        }
        catch (e) {
            // eslint-disable-next-line no-console
            console.error('Failed to revoke session', e);
        }
        return null;
    });
}
/**
 * Resolve the referrer url to be passed back to login, adjusted for the base path.
 */
export function resolveReferrer() {
    if (!window.dara.base_url) {
        return encodeURIComponent(window.location.pathname + window.location.search);
    }
    const base_url_path = new URL(window.dara.base_url, window.location.origin).pathname;
    const referrer = window.location.pathname;
    // Remove the matching part of the base_url from the referrer.
    let strippedReferrer = referrer.replace(base_url_path, '');
    // If this has stripped the leading / then replace it
    if (!strippedReferrer.startsWith('/')) {
        strippedReferrer = `/${strippedReferrer}`;
    }
    return encodeURIComponent(strippedReferrer + window.location.search);
}
/**
 * Helper function to handle auth errors in a response
 *
 * @param res the response object to check
 * @param toLogin if true, open the login page, else open the error page
 * @param ignoreErrors if specified, certain reasons for an error will be ignored
 */
export function handleAuthErrors(res_1) {
    return __awaiter(this, arguments, void 0, function* (res, toLogin = false, ignoreErrors = null) {
        var _a;
        // Bail out if the response is not an auth error, if we don't then non json responses can cause the following
        // code to hang.
        if (res.status >= 500 || res.status < 400) {
            return false;
        }
        const content = yield res.clone().json();
        const authError = parseAuthenticationError(content === null || content === void 0 ? void 0 : content.detail);
        if (authError && !shouldIgnoreError(authError, ignoreErrors !== null && ignoreErrors !== void 0 ? ignoreErrors : [])) {
            notifySessionLoggedOut();
            // use existing referrer if available in case we were already redirected because of e.g. missing token
            const queryParams = new URLSearchParams(window.location.search);
            const referrer = (_a = queryParams.get('referrer')) !== null && _a !== void 0 ? _a : resolveReferrer();
            const path = toLogin || shouldRedirectToLogin(authError) ? `/login?referrer=${referrer}` : `/error?code=${res.status}`;
            window.location.href = `${window.dara.base_url}${path}`;
            return true;
        }
        return false;
    });
}
/**
 * Api call to get user data from the backend
 */
export function useUser() {
    const extras = useRequestExtras();
    return useQuery({
        queryFn: () => __awaiter(this, void 0, void 0, function* () {
            const res = yield request('/api/auth/user', { method: HTTP_METHOD.GET }, extras);
            yield handleAuthErrors(res);
            yield validateResponse(res, 'Failed to fetch user for this app');
            return res.json();
        }),
        queryKey: ['user'],
        refetchOnWindowFocus: false,
    });
}
/** Api call to create a session with the backend */
export function requestSessionToken() {
    return __awaiter(this, arguments, void 0, function* (body = {}) {
        const res = yield request('/api/auth/session', {
            body: JSON.stringify(body),
            method: HTTP_METHOD.POST,
        });
        // check auth errors, but ignore invalid credentials - these will be handled by validateResponse further
        const loggedOut = yield handleAuthErrors(res, false, [AuthenticationErrorReason.INVALID_CREDENTIALS]);
        if (loggedOut) {
            return false;
        }
        yield validateResponse(res, 'Failed to create a session');
        return true;
    });
}
/** Api call to create a session with the backend */
export function useSession(body = {}) {
    return useQuery({
        queryFn: () => __awaiter(this, void 0, void 0, function* () {
            return requestSessionToken(body);
        }),
        queryKey: ['session'],
        refetchOnMount: false,
    });
}
/** Api call to verify the session token from the backend */
export function verifySessionToken() {
    return __awaiter(this, void 0, void 0, function* () {
        const res = yield request('/api/auth/verify-session', {
            method: HTTP_METHOD.POST,
        });
        if (!res.ok) {
            setSessionIdentifier(null);
            return false;
        }
        try {
            const sessionId = yield res.json();
            setSessionIdentifier(typeof sessionId === 'string' ? sessionId : null);
        }
        catch (_a) {
            setSessionIdentifier(null);
        }
        return true;
    });
}
//# sourceMappingURL=auth.js.map