"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isOAuthAllowed = isOAuthAllowed;
exports.getOAuthSettings = getOAuthSettings;
exports.isUserOAuthLogged = isUserOAuthLogged;
exports.getOAuthAccessToken = getOAuthAccessToken;
exports.removeOAuthCookies = removeOAuthCookies;
exports.saveOAuthTokensInCookies = saveOAuthTokensInCookies;
exports.getOAuthLoginPath = getOAuthLoginPath;
exports.getOAuthLogoutPath = getOAuthLogoutPath;
exports.refreshOAuthToken = refreshOAuthToken;
exports.exchangeOAuthToken = exchangeOAuthToken;
const axios_1 = __importDefault(require("axios"));
const node_crypto_1 = __importDefault(require("node:crypto"));
const constants_1 = require("../../shared/constants");
function getRedirectURL(req) {
    const config = getOAuthSettings(req);
    return config.callbackBaseUrl ?? `https://${req.get('host')}`;
}
function isOAuthAllowed(req) {
    const config = req.ctx.config.ytOAuthSettings;
    return Boolean(config &&
        config.baseURL &&
        config.authPath &&
        config.tokenPath &&
        config.clientId &&
        config.clientSecret);
}
function getOAuthSettings(req) {
    const config = req.ctx.config.ytOAuthSettings;
    if (!config) {
        throw new Error('OAuth settings is not specified');
    }
    return config;
}
function isUserOAuthLogged(req) {
    return (Boolean(req.cookies[constants_1.YT_OAUTH_ACCESS_TOKEN_NAME]) ||
        Boolean(req.cookies[constants_1.YT_OAUTH_REFRESH_TOKEN_NAME]));
}
async function getOAuthAccessToken(req, res) {
    if (req.cookies[constants_1.YT_OAUTH_ACCESS_TOKEN_NAME]) {
        return req.cookies[constants_1.YT_OAUTH_ACCESS_TOKEN_NAME];
    }
    else if (req.cookies[constants_1.YT_OAUTH_REFRESH_TOKEN_NAME]) {
        const tokens = await refreshOAuthToken(req, req.cookies[constants_1.YT_OAUTH_REFRESH_TOKEN_NAME]);
        saveOAuthTokensInCookies(res, tokens);
        return tokens.access_token;
    }
    return undefined;
}
function removeOAuthCookies(res) {
    res.clearCookie(constants_1.YT_OAUTH_ACCESS_TOKEN_NAME);
    res.clearCookie(constants_1.YT_OAUTH_REFRESH_TOKEN_NAME);
}
function saveOAuthTokensInCookies(res, tokens) {
    res.cookie(constants_1.YT_OAUTH_ACCESS_TOKEN_NAME, tokens.access_token, {
        maxAge: tokens.expires_in * 1000,
        httpOnly: true,
        secure: true,
    });
    if (tokens.refresh_token) {
        res.cookie(constants_1.YT_OAUTH_REFRESH_TOKEN_NAME, tokens.refresh_token, {
            maxAge: tokens.refresh_expires_in * 1000,
            httpOnly: true,
            secure: true,
        });
    }
}
function getOAuthLoginPath(req, res) {
    const { pathname, search, origin } = new URL(req.get('referrer') ?? '');
    const state = `state_${node_crypto_1.default.randomUUID()}`;
    res.cookie(state, { retPath: pathname + search });
    const config = getOAuthSettings(req);
    const params = new URLSearchParams({
        response_type: 'code',
        client_id: config.clientId,
        scope: config.scope,
        redirect_uri: `${config.callbackBaseUrl ?? origin ?? `https://${req.get('host')}`}/api/oauth/callback`,
        state,
    });
    const url = new URL(config.authPath, config.baseURL);
    url.search = params.toString();
    return url.toString();
}
function getOAuthLogoutPath(req) {
    const config = getOAuthSettings(req);
    if (!config.logoutPath) {
        return '/api/oauth/logout/callback';
    }
    const params = new URLSearchParams({
        post_logout_redirect_uri: `${getRedirectURL(req)}/api/oauth/logout/callback`,
        client_id: config.clientId,
    });
    const url = new URL(config.logoutPath, config.baseURL);
    url.search = params.toString();
    return url.toString();
}
async function refreshOAuthToken(req, token) {
    const config = getOAuthSettings(req);
    const params = new URLSearchParams({
        grant_type: 'refresh_token',
        client_id: config?.clientId,
        refresh_token: token,
        client_secret: config?.clientSecret,
    });
    const { data } = await axios_1.default.post(new URL(config.tokenPath, config.baseURL).toString(), params.toString(), {
        headers: {
            'Content-type': 'application/x-www-form-urlencoded',
        },
    });
    return data;
}
async function exchangeOAuthToken(req, code) {
    const config = getOAuthSettings(req);
    const params = new URLSearchParams({
        grant_type: 'authorization_code',
        client_id: config.clientId,
        code: code,
        client_secret: config.clientSecret,
        redirect_uri: `${getRedirectURL(req)}/api/oauth/callback`,
    });
    const { data } = await axios_1.default.post(new URL(config.tokenPath, config.baseURL).toString(), params.toString(), {
        headers: {
            'Content-type': 'application/x-www-form-urlencoded',
        },
    });
    return data;
}
