import { __awaiter, __decorate } from "tslib";
import { AuthError } from '@genesislcap/foundation-comms';
import { inIFrame, inSymphonyDesktop, openPopup } from '@genesislcap/foundation-utils';
import { customElement, DOM, observable, volatile } from '@microsoft/fast-element';
import { Route } from '@microsoft/fast-router';
import { logger } from '../../utils';
import { LoginFormStyles as styles } from './login-form.styles';
import { LoginFormTemplate as template } from './login-form.template';
import { BaseRoute } from '../base';
let LoginForm = class LoginForm extends BaseRoute {
    constructor() {
        super(...arguments);
        this.idps = [];
        this.selectedIDP = '';
        this.ssoToggled = false;
        this.fetchIDPs = () => __awaiter(this, void 0, void 0, function* () {
            var _a, _b;
            const fixEndpoint = (endpoint) => endpoint.startsWith('ws:')
                ? endpoint.replace('ws:', 'http:')
                : endpoint.startsWith('wss:')
                    ? endpoint.replace('wss:', 'https:')
                    : endpoint;
            const host = fixEndpoint(this.host);
            const ipdsEndpoint = `${host}${(_b = (_a = this.config.sso) === null || _a === void 0 ? void 0 : _a.identityProvidersPath) !== null && _b !== void 0 ? _b : 'sso/list'}`;
            return fetch(ipdsEndpoint)
                .then((res) => {
                if (res.ok)
                    return res;
                throw new Error(res.statusText);
            })
                .then((res) => res.json())
                .then((json) => json.IDPS);
        });
        this.toggleHttpMode = (e) => {
            if (!this.connect)
                return;
            // TODO: ability to swap between Connect and HttpConnect on the fly
            this.convertHostUrl();
        };
    }
    connectedCallback() {
        const _super = Object.create(null, {
            connectedCallback: { get: () => super.connectedCallback }
        });
        var _a, _b;
        return __awaiter(this, void 0, void 0, function* () {
            _super.connectedCallback.call(this);
            this.ssoToggled = (_b = (_a = this.config.sso) === null || _a === void 0 ? void 0 : _a.toggled) !== null && _b !== void 0 ? _b : false;
            if (this.connect.isConnected && this.auth.isLoggedIn) {
                yield this.credentialManager.preventSilentAccess();
                yield this.auth.logout();
            }
            this.convertHostUrl();
            yield this.autofill();
        });
    }
    enter() {
        return __awaiter(this, void 0, void 0, function* () {
            DOM.queueUpdate(() => __awaiter(this, void 0, void 0, function* () {
                try {
                    if (!this.connect.isConnected && this.config.autoConnect) {
                        yield this.toggleConnection();
                    }
                    if (!this.auth.isLoggedIn && this.config.autoAuth) {
                        this.attemptLoginWhenConnected();
                    }
                }
                catch (e) {
                    logger.debug(e);
                }
            }));
        });
    }
    toggleConnection() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.connect.isConnected) {
                this.connect.disconnect();
                logger.debug(`Disconnected from ${this.host}`);
                return;
            }
            return this.connect.connect(this.host);
        });
    }
    attemptLoginWhenConnected() {
        this.connect.isConnectedSubject.subscribe((isConnected) => {
            if (isConnected) {
                /**
                 * Login preference flow taken from @genesislcap/foundation-login.
                 * We should sit down with Jose and team to cross check this. Reference code is bit hard to follow in places.
                 */
                const cm = this.credentialManager;
                const refreshCredentials = cm.createRefreshCredentials();
                if (cm.validateRefreshCredentials(refreshCredentials)) {
                    logger.debug(`Attempting to login with refresh credentials.`);
                    this.login(refreshCredentials);
                    return;
                }
                if (this.ssoToggled) {
                    const ssoCredentials = cm.createSSOCredentials();
                    if (cm.validateSSOCredentials(ssoCredentials)) {
                        logger.debug(`Attempting to login with SSO.`);
                        this.login(ssoCredentials);
                        this.credentialManager.removeSSOToken(); // < sso tokens can only be used once, remove after login attempt
                        return;
                    }
                }
                this.attemptBasicLogin();
            }
        });
    }
    attemptBasicLogin() {
        const basicCredentials = this.credentialManager.createBasicCredentials({
            username: this.orgUsername,
            password: this.password,
        });
        if (!this.credentialManager.validateBasicCredentials(basicCredentials)) {
            logger.debug(`Basic credentials appear invalid, aborting login attempt.`);
            return;
        }
        logger.debug(`Attempting to login with basic credentials.`);
        this.login(basicCredentials);
    }
    ssoToggledChanged() {
        this.clearError();
        if (this.ssoToggled) {
            this.fetchIDPs()
                .then((idps) => {
                var _a, _b;
                logger.debug('fetched IDPs', idps);
                this.idps = idps.map((idp) => ({
                    id: idp.ID,
                    type: idp.TYPE,
                }));
                this.selectedIDP = (_b = (_a = this === null || this === void 0 ? void 0 : this.idps) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.id;
            })
                .catch(() => this.setError('Failed to fetch identity providers.'));
        }
    }
    get selectedIDPName() {
        return this.selectedIDP ? ` - ${this.selectedIDP}` : '';
    }
    onClickSSO() {
        const ssoLoginUrl = this.createLoginURL();
        if (inIFrame()) {
            if (inSymphonyDesktop()) {
                // symphony/electron opens new window in the default browser instead
                // popup within electron, so we have to navigate manually
                openPopup('', 'symphony').location.assign(ssoLoginUrl);
            }
            else {
                openPopup(ssoLoginUrl, 'Login');
            }
        }
        else {
            window.open(ssoLoginUrl, '_self');
        }
    }
    createLoginURL() {
        const selectedIDP = this.idps.find((idp) => idp.id === this.selectedIDP);
        const appHost = new URL(this.host).host;
        const ssoLoginRoute = `/gwf/${selectedIDP.type}/login`;
        const ssoLoginUrl = `https://${appHost}${ssoLoginRoute}?idp=${selectedIDP.id}`;
        return ssoLoginUrl;
    }
    convertHostUrl() {
        var _a, _b, _c, _d;
        if (((_a = this.connect) === null || _a === void 0 ? void 0 : _a.httpMode()) && ((_b = this.host) === null || _b === void 0 ? void 0 : _b.startsWith('ws'))) {
            this.host = this.host.replace('ws', 'http');
        }
        else if (!((_c = this.connect) === null || _c === void 0 ? void 0 : _c.httpMode()) && ((_d = this.host) === null || _d === void 0 ? void 0 : _d.startsWith('http'))) {
            this.host = this.host.replace('http', 'ws');
        }
    }
    onHostSubmit() {
        return __awaiter(this, void 0, void 0, function* () {
            logger.debug('host submission');
            yield this.toggleConnection();
        });
    }
    onLoginSubmit() {
        const _super = Object.create(null, {
            onSubmit: { get: () => super.onSubmit }
        });
        return __awaiter(this, void 0, void 0, function* () {
            logger.debug('login submission');
            yield _super.onSubmit.call(this);
            DOM.queueUpdate(() => {
                this.attemptBasicLogin();
            });
        });
    }
    login(credentials) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const { authToken } = yield this.auth.login(credentials);
                if (!authToken) {
                    throw new Error('Unable to login. Try again later.');
                }
                this.storeCredentials();
                let url = this.config.defaultRedirectUrl;
                if (this.session.returnUrl &&
                    !this.config.omitRedirectUrls.includes(this.session.returnUrl)) {
                    url = this.session.returnUrl;
                }
                Route.path.push(url);
            }
            catch (err) {
                if (err instanceof AuthError) {
                    if (err.hasPasswordExpiredError()) {
                        this.storeCredentials();
                        this.onNavigate('reset-password', { expired: true });
                        return;
                    }
                    if (this.config.fields.organisation && !this.organisation.length) {
                        this.setError(err.message + 'Please fill in Comp Id.');
                        return;
                    }
                    this.setError(err.message + err.getMessageError());
                    return;
                }
                this.setError(err.message);
            }
        });
    }
    get connectActionText() {
        return this.connect.isConnected ? 'Disconnect' : 'Connect';
    }
    get submitConnectDisabled() {
        return !this.host;
    }
    get submitDisabled() {
        return !this.connect.httpMode() && (this.connect.isWorking || !this.connect.isConnected);
    }
};
__decorate([
    observable
], LoginForm.prototype, "idps", void 0);
__decorate([
    observable
], LoginForm.prototype, "selectedIDP", void 0);
__decorate([
    observable
], LoginForm.prototype, "ssoToggled", void 0);
__decorate([
    volatile
], LoginForm.prototype, "selectedIDPName", null);
__decorate([
    volatile
], LoginForm.prototype, "connectActionText", null);
LoginForm = __decorate([
    customElement({
        name: 'foundation-login-form',
        template,
        styles,
    })
], LoginForm);
export { LoginForm };
//# sourceMappingURL=login-form.js.map