
import { decodeBase64 } from './buffer.js';

const WELL_KNOWN_ROUTE = '/.well-known';
const AUTH_SERVER_METADATA_DISCOVERY_PATH = `${WELL_KNOWN_ROUTE}/oauth-authorization-server`;
const OPENID_CONNECT_DISCOVERY_PATH = `${WELL_KNOWN_ROUTE}/openid-configuration`;
const AUTH_SCOPE_SEPARATOR = ' ';
var AuthorizationErrorType;
(function (AuthorizationErrorType) {
    AuthorizationErrorType["InvalidRequest"] = "invalid_request";
    AuthorizationErrorType["InvalidClient"] = "invalid_client";
    AuthorizationErrorType["InvalidGrant"] = "invalid_grant";
    AuthorizationErrorType["UnauthorizedClient"] = "unauthorized_client";
    AuthorizationErrorType["UnsupportedGrantType"] = "unsupported_grant_type";
    AuthorizationErrorType["InvalidScope"] = "invalid_scope";
})(AuthorizationErrorType || (AuthorizationErrorType = {}));
var AuthorizationDeviceCodeErrorType;
(function (AuthorizationDeviceCodeErrorType) {
    AuthorizationDeviceCodeErrorType["AuthorizationPending"] = "authorization_pending";
    AuthorizationDeviceCodeErrorType["SlowDown"] = "slow_down";
    AuthorizationDeviceCodeErrorType["AccessDenied"] = "access_denied";
    AuthorizationDeviceCodeErrorType["ExpiredToken"] = "expired_token";
})(AuthorizationDeviceCodeErrorType || (AuthorizationDeviceCodeErrorType = {}));
var AuthorizationRegistrationErrorType;
(function (AuthorizationRegistrationErrorType) {
    AuthorizationRegistrationErrorType["InvalidRedirectUri"] = "invalid_redirect_uri";
    AuthorizationRegistrationErrorType["InvalidClientMetadata"] = "invalid_client_metadata";
    AuthorizationRegistrationErrorType["InvalidSoftwareStatement"] = "invalid_software_statement";
    AuthorizationRegistrationErrorType["UnapprovedSoftwareStatement"] = "unapproved_software_statement";
})(AuthorizationRegistrationErrorType || (AuthorizationRegistrationErrorType = {}));
function isAuthorizationProtectedResourceMetadata(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return false;
    }
    const metadata = obj;
    return metadata.resource !== undefined;
}
function isAuthorizationServerMetadata(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return false;
    }
    const metadata = obj;
    return metadata.issuer !== undefined;
}
function isAuthorizationDynamicClientRegistrationResponse(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return false;
    }
    const response = obj;
    return response.client_id !== undefined;
}
function isAuthorizationTokenResponse(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return false;
    }
    const response = obj;
    return response.access_token !== undefined && response.token_type !== undefined;
}
function isAuthorizationErrorResponse(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return false;
    }
    const response = obj;
    return response.error !== undefined;
}
function isAuthorizationRegistrationErrorResponse(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return false;
    }
    const response = obj;
    return response.error !== undefined;
}
function getDefaultMetadataForUrl(authorizationServer) {
    return {
        issuer: ( authorizationServer.toString()),
        authorization_endpoint: ( ( new URL('/authorize', authorizationServer)).toString()),
        token_endpoint: ( ( new URL('/token', authorizationServer)).toString()),
        registration_endpoint: ( ( new URL('/register', authorizationServer)).toString()),
        response_types_supported: ['code', 'id_token', 'id_token token'],
    };
}
const grantTypesSupported = ['authorization_code', 'refresh_token', 'urn:ietf:params:oauth:grant-type:device_code'];
const DEFAULT_AUTH_FLOW_PORT = 33418;
async function fetchDynamicRegistration(serverMetadata, clientName, scopes) {
    if (!serverMetadata.registration_endpoint) {
        throw ( new Error('Server does not support dynamic registration'));
    }
    const response = await fetch(serverMetadata.registration_endpoint, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            client_name: clientName,
            client_uri: 'https://code.visualstudio.com',
            grant_types: serverMetadata.grant_types_supported
                ? serverMetadata.grant_types_supported.filter(gt => grantTypesSupported.includes(gt))
                : grantTypesSupported,
            response_types: ['code'],
            redirect_uris: [
                'https://insiders.vscode.dev/redirect',
                'https://vscode.dev/redirect',
                'http://localhost',
                'http://127.0.0.1',
                `http://localhost:${DEFAULT_AUTH_FLOW_PORT}`,
                `http://127.0.0.1:${DEFAULT_AUTH_FLOW_PORT}`
            ],
            scope: scopes?.join(AUTH_SCOPE_SEPARATOR),
            token_endpoint_auth_method: 'none',
            application_type: 'native'
        })
    });
    if (!response.ok) {
        const result = await response.text();
        let errorDetails = result;
        try {
            const errorResponse = JSON.parse(result);
            if (isAuthorizationRegistrationErrorResponse(errorResponse)) {
                errorDetails = `${errorResponse.error}${errorResponse.error_description ? `: ${errorResponse.error_description}` : ''}`;
            }
        }
        catch {
        }
        throw ( new Error(
            `Registration to ${serverMetadata.registration_endpoint} failed: ${errorDetails}`
        ));
    }
    const registration = await response.json();
    if (isAuthorizationDynamicClientRegistrationResponse(registration)) {
        return registration;
    }
    throw ( new Error(
        `Invalid authorization dynamic client registration response: ${JSON.stringify(registration)}`
    ));
}
function parseWWWAuthenticateHeader(wwwAuthenticateHeaderValue) {
    const parts = wwwAuthenticateHeaderValue.split(' ');
    const scheme = parts[0];
    const params = {};
    if (parts.length > 1) {
        const attributes = parts.slice(1).join(' ').split(',');
        attributes.forEach(attr => {
            const [key, value] = ( attr.split('=').map(s => s.trim().replace(/"/g, '')));
            params[key] = value;
        });
    }
    return { scheme, params };
}
function getClaimsFromJWT(token) {
    const parts = token.split('.');
    if (parts.length !== 3) {
        throw ( new Error('Invalid JWT token format: token must have three parts separated by dots'));
    }
    const [header, payload, _signature] = parts;
    try {
        const decodedHeader = JSON.parse(( decodeBase64(header).toString()));
        if (typeof decodedHeader !== 'object') {
            throw ( new Error('Invalid JWT token format: header is not a JSON object'));
        }
        const decodedPayload = JSON.parse(( decodeBase64(payload).toString()));
        if (typeof decodedPayload !== 'object') {
            throw ( new Error('Invalid JWT token format: payload is not a JSON object'));
        }
        return decodedPayload;
    }
    catch (e) {
        if (e instanceof Error) {
            throw ( new Error(`Failed to parse JWT token: ${e.message}`));
        }
        throw ( new Error('Failed to parse JWT token'));
    }
}

export { AUTH_SCOPE_SEPARATOR, AUTH_SERVER_METADATA_DISCOVERY_PATH, AuthorizationDeviceCodeErrorType, AuthorizationErrorType, AuthorizationRegistrationErrorType, DEFAULT_AUTH_FLOW_PORT, OPENID_CONNECT_DISCOVERY_PATH, fetchDynamicRegistration, getClaimsFromJWT, getDefaultMetadataForUrl, isAuthorizationDynamicClientRegistrationResponse, isAuthorizationErrorResponse, isAuthorizationProtectedResourceMetadata, isAuthorizationRegistrationErrorResponse, isAuthorizationServerMetadata, isAuthorizationTokenResponse, parseWWWAuthenticateHeader };
