import { __esDecorate, __runInitializers } from "tslib";
import { html, nothing } from 'lit';
import { SemanticType } from '@api-client/core/browser.js';
import { live } from 'lit/directives/live.js';
import { state } from 'lit/decorators.js';
import { ApiModelingScreen } from './ApiModelingScreen.js';
import { renderHelp } from '../../help/render.js';
let ApiModelingAccessScreen = (() => {
    let _classSuper = ApiModelingScreen;
    let _passwordProperty_decorators;
    let _passwordProperty_initializers = [];
    let _passwordProperty_extraInitializers = [];
    let _roleProperty_decorators;
    let _roleProperty_initializers = [];
    let _roleProperty_extraInitializers = [];
    return class ApiModelingAccessScreen extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _passwordProperty_decorators = [state()];
            _roleProperty_decorators = [state()];
            __esDecorate(this, null, _passwordProperty_decorators, { kind: "accessor", name: "passwordProperty", static: false, private: false, access: { has: obj => "passwordProperty" in obj, get: obj => obj.passwordProperty, set: (obj, value) => { obj.passwordProperty = value; } }, metadata: _metadata }, _passwordProperty_initializers, _passwordProperty_extraInitializers);
            __esDecorate(this, null, _roleProperty_decorators, { kind: "accessor", name: "roleProperty", static: false, private: false, access: { has: obj => "roleProperty" in obj, get: obj => obj.roleProperty, set: (obj, value) => { obj.roleProperty = value; } }, metadata: _metadata }, _roleProperty_initializers, _roleProperty_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #passwordProperty_accessor_storage = __runInitializers(this, _passwordProperty_initializers, null
        /**
         * A computed property from the data domain model that has the user role semantic tag.
         *
         * TODO:
         * - We should scan the entire data domain for UserRole semantic as likely there might be more than one.
         *   We should recommend the one on the `User` entity if multiple found.
         */
        );
        /**
         * A computed property from the data domain model that has the password semantic tag.
         */
        get passwordProperty() { return this.#passwordProperty_accessor_storage; }
        set passwordProperty(value) { this.#passwordProperty_accessor_storage = value; }
        #roleProperty_accessor_storage = (__runInitializers(this, _passwordProperty_extraInitializers), __runInitializers(this, _roleProperty_initializers, null));
        /**
         * A computed property from the data domain model that has the user role semantic tag.
         *
         * TODO:
         * - We should scan the entire data domain for UserRole semantic as likely there might be more than one.
         *   We should recommend the one on the `User` entity if multiple found.
         */
        get roleProperty() { return this.#roleProperty_accessor_storage; }
        set roleProperty(value) { this.#roleProperty_accessor_storage = value; }
        handleModelChange(model) {
            this.passwordProperty = null;
            this.roleProperty = null;
            if (!model) {
                return;
            }
            const domain = model.domain;
            if (!domain) {
                return;
            }
            // check local entities
            for (const entity of domain.listEntities()) {
                if (entity.hasSemantic(SemanticType.User)) {
                    this.analyzeUserEntity(entity);
                    return;
                }
            }
            // check foreign entities
            for (const entity of domain.listAllForeignEntities()) {
                if (entity.hasSemantic(SemanticType.User)) {
                    this.analyzeUserEntity(entity);
                    return;
                }
            }
        }
        analyzeUserEntity(entity) {
            let passwordProp = null;
            let roleProp = null;
            for (const property of entity.listProperties()) {
                if (property.hasSemantic(SemanticType.Password)) {
                    passwordProp = property;
                }
                if (property.hasSemantic(SemanticType.UserRole)) {
                    roleProp = property;
                }
                if (passwordProp && roleProp) {
                    break;
                }
            }
            this.passwordProperty = passwordProp;
            this.roleProperty = roleProp;
        }
        handleAuthStrategyChange(e) {
            const model = this.model;
            if (!model) {
                return;
            }
            const select = e.target;
            const { value } = select;
            if (model.authentication?.strategy === value) {
                // Ignore resetting the same value.
                return;
            }
            if (value === 'UsernamePassword') {
                if (!model.authentication || model.authentication.strategy !== 'UsernamePassword') {
                    model.authentication = {
                        strategy: 'UsernamePassword',
                    };
                }
            }
            else {
                // For now, only UsernamePassword is a valid, non-disabled option.
                // If other options are added, this logic will need to be expanded.
                if (!model.authentication) {
                    model.authentication = { strategy: value };
                }
                else {
                    model.authentication.strategy = value;
                }
            }
            this.model?.notifyChange();
            this.requestUpdate();
        }
        handleAuthzStrategyChange(e) {
            const model = this.model;
            if (!model) {
                return;
            }
            const select = e.target;
            const { value } = select;
            if (model.authorization?.strategy === value) {
                // Ignore resetting the same value.
                return;
            }
            if (value === 'RBAC') {
                if (!model.authorization || model.authorization.strategy !== 'RBAC') {
                    model.authorization = {
                        strategy: 'RBAC',
                        roleKey: this.roleProperty?.key || '', // default value
                    };
                }
            }
            else {
                // For now, only RBAC is a valid, non-disabled option.
                if (!model.authorization) {
                    model.authorization = { strategy: value };
                }
                else {
                    model.authorization.strategy = value;
                }
            }
            this.model?.notifyChange();
            this.requestUpdate();
        }
        handleAccessConfigChange() {
            this.model?.notifyChange();
        }
        render() {
            const model = this.model;
            if (!model) {
                return nothing;
            }
            return html `
      <div class="screen-container">
        <div class="screen-header">
          <h2 class="headline-medium">API Access</h2>
          <span class="body-medium description">
            API access allows you to control how your API customers access the API. Here, you can configure the
            authentication strategy and global access rules. You can update these settings for each behaviors
            separately.
          </span>
        </div>
        ${this.renderAuthentication(model)} ${this.renderAuthorization(model)} ${this.renderApiAccessConfiguration()}
      </div>
    `;
        }
        renderAuthentication(model) {
            const authStrategy = model.authentication?.strategy;
            return html `
      <div class="config-section authentication">
        <div class="section-header">
          <h3 class="title-large">Authentication strategy</h3>
          <span class="body-small description">
            Choose how your API will verify the identity of its users. You can change these settings until you first
            deploy your API. After that the change won't be possible.
          </span>
        </div>
        <div class="row">
          <ui-select
            label="Strategy"
            name="authenticationStrategy"
            .value="${live(authStrategy)}"
            @change="${this.handleAuthStrategyChange}"
          >
            <ui-option value="UsernamePassword">
              <div>Username and Password</div>
              <div slot="supporting-text">Authenticate with a username and password.</div>
            </ui-option>
            <ui-option value="SSO" disabled>
              <div>Single Sign-On</div>
              <div slot="supporting-text">Coming soon</div>
            </ui-option>
          </ui-select>
          ${renderHelp('api', 'auth-strategy-select')}
        </div>

        ${this.renderPasswordConfirmation(model)}
      </div>
    `;
        }
        renderPasswordConfirmation(model) {
            const strategy = model.authentication?.strategy;
            if (strategy !== 'UsernamePassword') {
                return nothing;
            }
            const prop = this.passwordProperty;
            if (!prop) {
                return html `<span class="body-small no-property-warning">
        <ui-icon>warning_amber</ui-icon>
        No password property found on the user entity. Please define one on the data domain's User entity to ensure
        secure authentication.
      </span>`;
            }
            return html `<span class="body-small property-info"
      >Password property: <strong>${prop.info.getLabel()}</strong></span
    >`;
        }
        renderAuthorization(model) {
            const authzStrategy = model.authorization?.strategy || '';
            return html `
      <div class="config-section authorization">
        <div class="section-header">
          <h2 class="title-large">Authorization strategy</h2>
          <span class="body-medium description">
            It allows you to configure how users access data in your API. After the authorization strategy is set it
            cannot be changed.
          </span>
        </div>
        <div class="row">
          <ui-select
            label="Strategy"
            name="authorizationStrategy"
            .value="${live(authzStrategy)}"
            @change="${this.handleAuthzStrategyChange}"
          >
            <ui-option value="RBAC">
              <div>Role-based authentication</div>
              <div slot="supporting-text">Access is granted based on user roles.</div>
            </ui-option>
            <ui-option value="PBAC" disabled>
              <div>Permission-based authentication</div>
              <div slot="supporting-text">Coming soon</div>
            </ui-option>
          </ui-select>
          ${renderHelp('api', 'authz-strategy-select')}
        </div>
        ${this.renderRoleConfirmation(model)}
      </div>
    `;
        }
        renderRoleConfirmation(model) {
            const strategy = model.authorization?.strategy || '';
            if (strategy !== 'RBAC') {
                return nothing;
            }
            const prop = this.roleProperty;
            if (!prop) {
                return html `<span class="body-small no-property-warning">
        <ui-icon>warning_amber</ui-icon>
        No role property found on the user entity. Please define one on the data domain's User entity to ensure proper
        authorization.
      </span>`;
            }
            return html `<span class="body-small property-info">Role property: <strong>${prop.info.getLabel()}</strong></span>`;
        }
        renderApiAccessConfiguration() {
            return html `<api-modeling-access-configuration
      .model=${this.model}
      target="api"
      @change=${this.handleAccessConfigChange}
      class="api-access-configuration"
    ></api-modeling-access-configuration>`;
        }
        constructor() {
            super(...arguments);
            __runInitializers(this, _roleProperty_extraInitializers);
        }
    };
})();
/**
 * A screen for editing API access information.
 * Used in API modeling.
 *
 * Note that unlike configuration components, screens alter the model directly
 * and notify changes as needed (on the model).
 */
export default ApiModelingAccessScreen;
//# sourceMappingURL=ApiModelingAccessScreen.js.map