import AppConfig from "../lib/appConfig.js";
import constants from "../lib/constants.js";
import RESTClient from "../lib/restClient.js";
export default class LoginManager {
    cssRoot;
    endpoint;
    password;
    token;
    tokenTimestamp;
    username;
    async getCssRoot() {
        await this.loadCredentials();
        return this.cssRoot;
    }
    getUserString() {
        if (!this.username || !this.endpoint) {
            return "(none)";
        }
        const { host } = new URL(this.endpoint);
        return `${this.username}@${host}`;
    }
    hasCredentials() {
        return Boolean(this.username && this.password && this.endpoint);
    }
    async login(force = false) {
        await this.loadCredentials();
        if (!this.endpoint || !this.password || !this.username) {
            throw new Error(`This operation requires you to log in with your application credentials first. Please try \`${constants.APP_NAME} login --help\`.`);
        }
        if (!force && this.token && (this.tokenTimestamp || 0) + constants.TOKEN_VALIDITY_TIMEOUT_MS > Date.now()) {
            return this.token;
        }
        try {
            const restClient = new RESTClient(this.endpoint);
            const tokenResponse = await restClient.post(constants.LOGIN_ENDPOINT_URI, undefined, undefined, { Authorization: `Basic ${Buffer.from(`${this.username}:${this.password}`).toString('base64')}` });
            const { css_root: cssRoot, token } = tokenResponse;
            this.token = token;
            this.tokenTimestamp = Date.now();
            if (cssRoot) {
                this.cssRoot = cssRoot;
            }
            await this.flushCredentials();
            return token;
        }
        catch (error) {
            if (error instanceof Error) {
                // eslint-disable-next-line unicorn/prefer-type-error
                throw new Error(`Login failed: ${error.message}. Please check your credentials and try again.`);
            }
            throw error;
        }
    }
    async logout() {
        this.cssRoot = undefined;
        this.token = undefined;
        this.tokenTimestamp = undefined;
        this.username = undefined;
        this.password = undefined;
        this.endpoint = undefined;
        await this.flushCredentials();
    }
    async setCredentials(endpoint, password, username) {
        this.endpoint = this.normalizeEndpoint(endpoint);
        this.password = password;
        this.username = username;
        await this.flushCredentials();
    }
    async flushCredentials() {
        const appConfig = await AppConfig.getInstance();
        appConfig.setConfig("username", this.username);
        appConfig.setConfig("password", this.password);
        appConfig.setConfig("endpoint", this.endpoint);
        appConfig.setConfig("token", this.token);
        appConfig.setConfig("tokenTimestamp", this.tokenTimestamp);
        appConfig.setConfig("cssRoot", this.cssRoot);
    }
    async loadCredentials() {
        if (this.username && this.password && this.endpoint) {
            return;
        }
        const appConfig = await AppConfig.getInstance();
        this.username = await appConfig.getConfig("username");
        this.password = await appConfig.getConfig("password");
        this.endpoint = await appConfig.getConfig("endpoint");
        this.token = await appConfig.getConfig("token");
        this.tokenTimestamp = await appConfig.getConfig("tokenTimestamp");
        this.cssRoot = await appConfig.getConfig("cssRoot");
    }
    normalizeEndpoint(url) {
        try {
            if (!/^https?:\/\//i.test(url)) {
                url = `https://${url}`;
            }
            const parsedUrl = new URL(url);
            if (parsedUrl.protocol !== 'https:') {
                throw new Error("Invalid protocol");
            }
            const { hostname } = parsedUrl;
            const portStr = parsedUrl.port ? `:${parsedUrl.port}` : '';
            return `https://${hostname}${portStr}`;
        }
        catch {
            throw new Error("Invalid URL format");
        }
    }
}
