import { __decorate } from "tslib";
import { html } from 'lit';
import { property, queryAll } from 'lit/decorators.js';
import ApiElement from '../ApiElement.js';
import '../../define/amf/authorization/amf-basic-authorization.js';
import '../../define/amf/authorization/amf-passthrough-authorization.js';
import '../../define/amf/authorization/amf-bearer-authorization.js';
import '../../define/amf/authorization/amf-apikey-authorization.js';
import '../../define/amf/authorization/amf-ramlcustom-authorization.js';
import '../../define/amf/authorization/amf-oauth2-authorization.js';
import '../../define/amf/authorization/amf-oidc-authorization.js';
export default class ApiAuthorizationEditor extends ApiElement {
    get security() {
        return this.securityInternal;
    }
    set security(value) {
        const old = this.securityInternal;
        if (old === value) {
            return;
        }
        this.securityInternal = value;
        this.processModel();
        this.requestUpdate();
    }
    get methods() {
        return this.methodsInternal;
    }
    /**
     * Reads list of authorization methods from the model.
     */
    processModel() {
        const security = this.securityInternal;
        if (!security) {
            return;
        }
        this.methodsInternal = this.computeMethods(security.schemes);
    }
    /**
     * Computes list of security schemes that can be applied to the element.
     *
     * @param schemes A list of security schemes to process.
     * @returns A list of authorization methods that can be applied to
     * the current endpoint. Each object describes the list of security types
     * that can be applied to the editor. In OAS an auth method may be an union
     * of methods.
     */
    computeMethods(schemes) {
        const result = {
            types: [],
            schemes: [],
        };
        schemes.forEach((security) => {
            const type = this.listSchemeLabels(security);
            if (!type) {
                return;
            }
            result.types.push(type);
            result.schemes.push(security);
        });
        return result;
    }
    /**
     * Reads authorization scheme's name and type from the AMF model.
     */
    listSchemeLabels(security) {
        const { name, scheme } = security;
        if (name === 'null') {
            // RAML allows to define a "null" scheme. This means that the authorization
            // for this endpoint is optional.
            return 'No authorization';
        }
        if (!scheme) {
            return undefined;
        }
        let { type } = scheme;
        if (type === 'http') {
            // HTTP type can be `basic` or `bearer`.
            const config = scheme.settings;
            if (!config) {
                // this happens when AMF doesn't properly read graph model back to the store.
                // AMF team promised to fix this...
                type = undefined;
            }
            else {
                type = config.scheme;
            }
        }
        return type;
    }
    /**
     * A function called each time anything change in the editor.
     * Revalidates the component and dispatches the `change` event.
     */
    changeHandler() {
        this.validate();
        this.notifyChange();
    }
    /**
     * Validates state of the editor. It sets `invalid` property when called.
     *
     * Exception: OAuth 2 form reports valid even when the `accessToken` is not
     * set. This adjust for this and reports invalid when `accessToken` for OAuth 2
     * is missing.
     *
     * @returns True when the form has valid data.
     */
    validate() {
        const { editors } = this;
        let valid = true;
        for (let i = 0, len = editors.length; i < len; i++) {
            const node = editors[i];
            const methodValid = node.checkValidity();
            if (!methodValid) {
                valid = methodValid;
                break;
            }
            // if (['amf-oauth2-authorization', 'amf-oidc-authorization'].includes(node.localName)) {
            //   const oauth = node as OAuth2Authorization;
            //   const { config } = oauth;
            //   if (!config.accessToken) {
            //     valid = false;
            //     break;
            //   }
            // }
        }
        this.invalid = !valid;
        return valid;
    }
    /**
     * Creates a list of configuration by calling the `serialize()` function on each
     * currently rendered authorization form.
     *
     * @returns List of authorization settings.
     */
    serialize() {
        const { editors } = this;
        return Array.from(editors).map((editor) => {
            const auth = editor.authorization;
            auth.valid = editor.checkValidity();
            return auth;
        });
    }
    /**
     * Calls the `authorize()` function on each rendered authorization methods.
     * Currently only `OAuth 1.0` and `OAuth 2.0` actually perform the authorization.
     *
     * Each method is called in order to make sure the user is not overwhelmed with
     * dialogs or other UI elements.
     *
     * The function rejects when at least one authorization method rejects.
     */
    async authorize() {
        const { editors } = this;
        const list = Array.from(editors);
        while (list.length) {
            const auth = list.shift();
            if (!auth) {
                break;
            }
            // eslint-disable-next-line no-await-in-loop
            await auth.authorize();
        }
    }
    render() {
        const methods = this.methodsInternal;
        if (!methods || !methods.schemes.length) {
            return html ``;
        }
        return html `
    <section class="authorization-union">
    ${methods.schemes.map((scheme, index) => this.methodTemplate(scheme, methods.types[index]))}
    </section>
    `;
    }
    methodTemplate(scheme, type) {
        switch (type) {
            case 'Basic Authentication':
            case 'basic':
                return this.basicAuthTemplate(scheme);
            case 'Digest Authentication':
                return this.digestAuthTemplate();
            case 'Pass Through':
                return this.passThroughAuthTemplate(scheme);
            case 'OAuth 2.0':
                return this.oa2AuthTemplate(scheme);
            case 'OAuth 1.0':
                return this.oa1AuthTemplate();
            case 'bearer':
                return this.bearerAuthTemplate(scheme);
            case 'Api Key':
                return this.apiKeyTemplate(scheme);
            case 'openIdConnect':
                return this.openIdConnectTemplate(scheme);
            default:
                if (String(type).indexOf('x-') === 0) {
                    return this.ramlCustomAuthTemplate(scheme);
                }
        }
        return '';
    }
    /**
     * Renders a template for Basic authorization.
     */
    basicAuthTemplate(security) {
        return html `
    <amf-basic-authorization .security="${security}" @change="${this.changeHandler}" class="auth-editor"></amf-basic-authorization>`;
    }
    /**
     * Renders a template for Digest authorization.
     */
    digestAuthTemplate() {
        return html `
    <p class="no-support digest">The Digest authorization is not longer supported.</p>
    `;
    }
    /**
     * Renders a template for Pass through authorization.
     */
    passThroughAuthTemplate(security) {
        return html `
    <amf-passthrough-authorization .security="${security}" @change="${this.changeHandler}" class="auth-editor"></amf-passthrough-authorization>`;
    }
    /**
     * Renders a template for RAML custom authorization.
     */
    ramlCustomAuthTemplate(security) {
        return html `<amf-ramlcustom-authorization .security="${security}" @change="${this.changeHandler}" class="auth-editor"></amf-ramlcustom-authorization>`;
    }
    /**
     * Renders a template for Bearer authorization (OAS).
     */
    bearerAuthTemplate(security) {
        return html `
    <amf-bearer-authorization .security="${security}" @change="${this.changeHandler}" class="auth-editor"></amf-bearer-authorization>`;
    }
    /**
     * Renders a template for OAuth 1 authorization.
     */
    oa1AuthTemplate() {
        return html `
    <p class="no-support oauth1">The OAuth1 authorization is not longer supported.</p>
    `;
    }
    /**
     * Renders a template for OAuth 2 authorization.
     */
    oa2AuthTemplate(security) {
        const { oauth2RedirectUri, credentialsSource, oauth2AuthorizationUri, oauth2AccessTokenUri, } = this;
        return html `
    <amf-oauth2-authorization
      .defaultRedirectUri="${oauth2RedirectUri}"
      .overrideAuthorizationUri="${oauth2AuthorizationUri}"
      .overrideAccessTokenUri="${oauth2AccessTokenUri}"
      .security="${security}"
      .credentialsSource="${credentialsSource}"
      @change="${this.changeHandler}"
      class="auth-editor"
    ></amf-oauth2-authorization>`;
    }
    /**
     * Renders a template for OAuth 2 authorization.
     */
    openIdConnectTemplate(security) {
        const { oauth2RedirectUri, credentialsSource, } = this;
        return html `
    <amf-oidc-authorization
      .defaultRedirectUri="${oauth2RedirectUri}"
      .security="${security}"
      .credentialsSource="${credentialsSource}"
      @change="${this.changeHandler}"
      class="auth-editor"
    ></amf-oidc-authorization>`;
    }
    /**
     * Renders a template for Api Keys authorization.
     */
    apiKeyTemplate(security) {
        return html `
    <amf-apikey-authorization .security="${security}" @change="${this.changeHandler}" class="auth-editor"></amf-apikey-authorization>
    `;
    }
}
__decorate([
    property({ type: Boolean, reflect: true })
], ApiAuthorizationEditor.prototype, "invalid", void 0);
__decorate([
    property({ type: Array })
], ApiAuthorizationEditor.prototype, "credentialsSource", void 0);
__decorate([
    property({ type: String })
], ApiAuthorizationEditor.prototype, "oauth2RedirectUri", void 0);
__decorate([
    property({ type: String })
], ApiAuthorizationEditor.prototype, "oauth2AuthorizationUri", void 0);
__decorate([
    property({ type: String })
], ApiAuthorizationEditor.prototype, "oauth2AccessTokenUri", void 0);
__decorate([
    queryAll('.auth-editor')
], ApiAuthorizationEditor.prototype, "editors", void 0);
//# sourceMappingURL=ApiAuthorizationEditor.element.js.map