import { __esDecorate, __runInitializers } from "tslib";
import { html, nothing } from 'lit';
import { property, state } from 'lit/decorators.js';
import { Kind as HttpProjectKind } from '@api-client/core/models/HttpProject.js';
import { HeadersArray } from '@api-client/core/models/HeadersArray.js';
import { RequestConfig } from '@api-client/core/models/RequestConfig.js';
import { RequestAuthorization } from '@api-client/core/models/RequestAuthorization.js';
import { Kind as HttpHistoryKind } from '@api-client/core/models/HttpHistory.js';
import { Events as CoreEvents } from '@api-client/core/events/Events.js';
import RequestEditor from '../http/RequestEditor.js';
// import { Events } from '../../events/Events.js'
import { EventTypes } from '../../events/EventTypes.js';
import { midnightTimestamp } from '../../lib/time/Conversion.js';
import '../../md/icons/ui-icon.js';
import '../../md/button/ui-button.js';
import '../../md/dropdown-list/ui-dropdown-list.js';
import '../../md/list/ui-list.js';
import '../../md/list/ui-list-item.js';
function stopEvent(e) {
    e.stopPropagation();
}
let HttpProjectRequest = (() => {
    let _classSuper = RequestEditor;
    let _sharedVariables_decorators;
    let _sharedVariables_initializers = [];
    let _sharedVariables_extraInitializers = [];
    let _project_decorators;
    let _project_initializers = [];
    let _project_extraInitializers = [];
    let _key_decorators;
    let _key_initializers = [];
    let _key_extraInitializers = [];
    let _appInfo_decorators;
    let _appInfo_initializers = [];
    let _appInfo_extraInitializers = [];
    let _environments_decorators;
    let _environments_initializers = [];
    let _environments_extraInitializers = [];
    let _environmentLabel_decorators;
    let _environmentLabel_initializers = [];
    let _environmentLabel_extraInitializers = [];
    let _useNetStore_decorators;
    let _useNetStore_initializers = [];
    let _useNetStore_extraInitializers = [];
    return class HttpProjectRequest extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _sharedVariables_decorators = [property({ type: Object })];
            _project_decorators = [property({ type: Object })];
            _key_decorators = [property({ type: String, reflect: true })];
            _appInfo_decorators = [property({ type: Object })];
            _environments_decorators = [state()];
            _environmentLabel_decorators = [state()];
            _useNetStore_decorators = [property({ type: Boolean })];
            __esDecorate(this, null, _sharedVariables_decorators, { kind: "accessor", name: "sharedVariables", static: false, private: false, access: { has: obj => "sharedVariables" in obj, get: obj => obj.sharedVariables, set: (obj, value) => { obj.sharedVariables = value; } }, metadata: _metadata }, _sharedVariables_initializers, _sharedVariables_extraInitializers);
            __esDecorate(this, null, _project_decorators, { kind: "accessor", name: "project", static: false, private: false, access: { has: obj => "project" in obj, get: obj => obj.project, set: (obj, value) => { obj.project = value; } }, metadata: _metadata }, _project_initializers, _project_extraInitializers);
            __esDecorate(this, null, _key_decorators, { kind: "accessor", name: "key", static: false, private: false, access: { has: obj => "key" in obj, get: obj => obj.key, set: (obj, value) => { obj.key = value; } }, metadata: _metadata }, _key_initializers, _key_extraInitializers);
            __esDecorate(this, null, _appInfo_decorators, { kind: "accessor", name: "appInfo", static: false, private: false, access: { has: obj => "appInfo" in obj, get: obj => obj.appInfo, set: (obj, value) => { obj.appInfo = value; } }, metadata: _metadata }, _appInfo_initializers, _appInfo_extraInitializers);
            __esDecorate(this, null, _environments_decorators, { kind: "accessor", name: "environments", static: false, private: false, access: { has: obj => "environments" in obj, get: obj => obj.environments, set: (obj, value) => { obj.environments = value; } }, metadata: _metadata }, _environments_initializers, _environments_extraInitializers);
            __esDecorate(this, null, _environmentLabel_decorators, { kind: "accessor", name: "environmentLabel", static: false, private: false, access: { has: obj => "environmentLabel" in obj, get: obj => obj.environmentLabel, set: (obj, value) => { obj.environmentLabel = value; } }, metadata: _metadata }, _environmentLabel_initializers, _environmentLabel_extraInitializers);
            __esDecorate(this, null, _useNetStore_decorators, { kind: "accessor", name: "useNetStore", static: false, private: false, access: { has: obj => "useNetStore" in obj, get: obj => obj.useNetStore, set: (obj, value) => { obj.useNetStore = value; } }, metadata: _metadata }, _useNetStore_initializers, _useNetStore_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #sharedVariables_accessor_storage = __runInitializers(this, _sharedVariables_initializers, void 0);
        /**
         * A reference to the global shared variables.
         * Used with the communication with the execution server.
         */
        get sharedVariables() { return this.#sharedVariables_accessor_storage; }
        set sharedVariables(value) { this.#sharedVariables_accessor_storage = value; }
        #project_accessor_storage = (__runInitializers(this, _sharedVariables_extraInitializers), __runInitializers(this, _project_initializers, void 0));
        /**
         * The source project
         */
        get project() { return this.#project_accessor_storage; }
        set project(value) { this.#project_accessor_storage = value; }
        #key_accessor_storage = (__runInitializers(this, _project_extraInitializers), __runInitializers(this, _key_initializers, void 0));
        /**
         * The key of the request being processed.
         * @attribute
         */
        get key() { return this.#key_accessor_storage; }
        set key(value) { this.#key_accessor_storage = value; }
        #appInfo_accessor_storage = (__runInitializers(this, _key_extraInitializers), __runInitializers(this, _appInfo_initializers, void 0));
        /**
         * This property is required for the API access to work.
         * Set it to the current application information.
         */
        get appInfo() { return this.#appInfo_accessor_storage; }
        set appInfo(value) { this.#appInfo_accessor_storage = value; }
        /**
         * The read `expects` value from the project request.
         */
        expects = __runInitializers(this, _appInfo_extraInitializers);
        /**
         * The read project request object from the project.
         */
        projectRequest;
        #environments_accessor_storage = __runInitializers(this, _environments_initializers, void 0);
        /**
         * The list of environments that apply to the current request.
         */
        get environments() { return this.#environments_accessor_storage; }
        set environments(value) { this.#environments_accessor_storage = value; }
        #environmentLabel_accessor_storage = (__runInitializers(this, _environments_extraInitializers), __runInitializers(this, _environmentLabel_initializers, void 0));
        /**
         * Computed value of the environment to render in the environment selector.
         * Because of the complexity of finding the name, it is computed on `environment` change only.
         */
        get environmentLabel() { return this.#environmentLabel_accessor_storage; }
        set environmentLabel(value) { this.#environmentLabel_accessor_storage = value; }
        #useNetStore_accessor_storage = (__runInitializers(this, _environmentLabel_extraInitializers), __runInitializers(this, _useNetStore_initializers, void 0));
        /**
         * When set the requests sent from the editor will contain the entire project serialized with the request
         * rather just the id of the project. This is used in HTTP Client that doesn't use the net-store
         * and uses local proxy.
         * @attribute
         */
        get useNetStore() { return this.#useNetStore_accessor_storage; }
        set useNetStore(value) { this.#useNetStore_accessor_storage = value; }
        constructor() {
            super();
            __runInitializers(this, _useNetStore_extraInitializers);
            // do not propagate HTTP request internal events outside as multiple requests are rendered in the same document.
            this.eventsTarget = this;
            this.addEventListener(EventTypes.Http.Request.State.urlChange, stopEvent);
            this.addEventListener(EventTypes.Http.Request.State.contentTypeChange, stopEvent);
        }
        willUpdate(cp) {
            if (cp.has('project') || cp.has('key')) {
                this.setupRequest();
            }
            super.willUpdate(cp);
        }
        applyPatch(info) {
            const { projectRequest } = this;
            if (!projectRequest) {
                return;
            }
            if (info.path.startsWith('/definitions/environments')) {
                // environments changed.
                this.setupRequestEnvironments(projectRequest);
                return;
            }
            // "/definitions/requests/\d+/..."
            const parts = info.path.split('/').slice(4);
            const [root] = parts;
            if (root === 'expects' || root === 'log') {
                this.setupRequest();
            }
        }
        cleanup() {
            this.expects = undefined;
            this.environments = undefined;
            this.ui = undefined;
        }
        setupRequest() {
            const { project, key } = this;
            if (!project || !key) {
                this.cleanup();
                return;
            }
            const request = project.findRequest(key);
            if (!request) {
                this.cleanup();
                return;
            }
            this.projectRequest = request;
            const expects = request.getExpects();
            this.expects = expects;
            this.request = expects.toJSON();
            this.authorization = request.authorization?.map((i) => i.toJSON());
            this.assertions = request.assertions;
            this.flows = request.flows;
            if (request.config) {
                this.config = request.config.toJSON();
            }
            this.setupRequestEnvironments(request);
            this.computeSnippetsRequest();
            this.requestUpdate();
        }
        /**
         * Reads environments to be applies to the request and sets up local variables.
         */
        setupRequestEnvironments(request) {
            this.environments = request.readEnvironments();
            this.computeEnvironmentLabel();
            this.computeSnippetsRequest();
        }
        selectVerb(verb) {
            const { expects } = this;
            if (!expects) {
                return;
            }
            expects.method = verb;
            super.selectVerb(verb);
        }
        selectUrl(value) {
            const { expects } = this;
            if (!expects) {
                return;
            }
            expects.url = value;
            super.selectUrl(value);
        }
        selectHeaders(model) {
            const { expects } = this;
            if (!expects) {
                return;
            }
            expects.headersModel = HeadersArray.from(model);
            super.selectHeaders(model);
        }
        selectAssertions(assertions) {
            const { projectRequest } = this;
            if (!projectRequest) {
                return;
            }
            projectRequest.assertions = assertions;
            super.selectAssertions(assertions);
        }
        selectFlows(flows) {
            const { projectRequest } = this;
            if (!projectRequest) {
                return;
            }
            projectRequest.flows = flows;
            super.selectFlows(flows);
        }
        selectRequestConfig(config) {
            const { projectRequest } = this;
            if (!projectRequest) {
                return;
            }
            projectRequest.config = new RequestConfig(config);
            super.selectRequestConfig(config);
        }
        async updatePayload(value, mime) {
            const { expects } = this;
            if (!expects) {
                return;
            }
            await expects.writePayload(value);
            this.setPayloadMimeOption(expects, mime);
            await super.updatePayload(value, mime);
        }
        addAuthorization(type) {
            const schema = super.addAuthorization(type);
            if (this.projectRequest) {
                if (!this.projectRequest.authorization) {
                    this.projectRequest.authorization = [];
                }
                this.projectRequest.authorization.push(schema);
                this.notifyChange();
            }
            return schema;
        }
        updateAuthorization(schema, isValid) {
            super.updateAuthorization(schema, isValid);
            const { projectRequest } = this;
            if (!projectRequest) {
                return;
            }
            if (!projectRequest.authorization) {
                // somehow invalid state. These should be in sync...
                return;
            }
            const index = projectRequest.authorization.findIndex((i) => i.type === schema.type);
            if (index === -1) {
                return;
            }
            projectRequest.authorization[index] = new RequestAuthorization(schema);
            this.notifyChange();
        }
        removeAuthorization(type) {
            super.removeAuthorization(type);
            const { projectRequest } = this;
            if (!projectRequest) {
                return;
            }
            if (!projectRequest.authorization) {
                return;
            }
            const index = projectRequest.authorization.findIndex((i) => i.type === type);
            if (index === -1) {
                return;
            }
            projectRequest.authorization.splice(index, 1);
            this.notifyChange();
        }
        notifySend() {
            this.execute();
        }
        prepareProxyInit(project, key, request) {
            const { sharedVariables } = this;
            const options = {
                environment: request.environment,
                request: [key],
                recursive: true,
            };
            if (sharedVariables) {
                options.variables = sharedVariables;
            }
            if (this.useNetStore) {
                return {
                    kind: HttpProjectKind,
                    pid: project.key,
                    options,
                };
            }
            return {
                project: project.toJSON(),
                kind: HttpProjectKind,
                options,
            };
        }
        async proxyRequest(init) {
            let result;
            try {
                result = await CoreEvents.Transport.Core.httpProject(init, this);
            }
            catch {
                // ...
            }
            return result;
        }
        async execute() {
            const { project, key, projectRequest } = this;
            if (!project || !key || !projectRequest) {
                throw new Error(`The project request is not initialized.`);
            }
            const init = this.prepareProxyInit(project, key, projectRequest);
            this.loading = true;
            const result = await this.proxyRequest(init);
            if (result && result.result) {
                const [iteration] = result.result.iterations;
                if (iteration) {
                    const { executed, variables } = iteration;
                    if (variables) {
                        this.mergeExecutedVariables(variables);
                    }
                    const [report] = executed;
                    if (report) {
                        this.addHistory(report);
                        this.requestUpdate();
                    }
                }
            }
            this.loading = false;
        }
        mergeExecutedVariables(vars) {
            const { sharedVariables } = this;
            if (!sharedVariables) {
                return;
            }
            Object.keys(vars).forEach((key) => {
                sharedVariables[key] = vars[key];
            });
        }
        async addHistory(report) {
            const { appInfo, project, key } = this;
            if (!appInfo) {
                throw new Error(`The appInfo is not set on ${this.localName}`);
            }
            if (!project || !key) {
                return;
            }
            const item = {
                created: Date.now(),
                kind: HttpHistoryKind,
                log: report,
                project: project.key,
                app: appInfo.code,
                request: key,
                user: '', // added by the bindings
                midnight: midnightTimestamp(),
                key: '',
                organization: '', // will be filled by the bindings.
            };
            // Events.Store.History.create(item)
            throw new Error(`Not yet implemented: ${item}`);
        }
        handleEnvironmentSelection(e) {
            const { projectRequest } = this;
            const target = e.detail.item;
            if (!target || !projectRequest) {
                return;
            }
            const { key } = target.dataset;
            if (projectRequest.environment === key) {
                return;
            }
            projectRequest.environment = key;
            this.computeEnvironmentLabel();
            projectRequest.environment = key;
            this.computeSnippetsRequest();
            this.notifyChange();
            this.notifyPropertyChanged('environment', key);
        }
        computeEnvironmentLabel() {
            const { projectRequest } = this;
            if (!projectRequest) {
                this.environmentLabel = undefined;
                return;
            }
            const url = projectRequest.readUrl({ baseUrl: true, noVariables: true });
            this.environmentLabel = url || 'No server defined';
        }
        async computeSnippetsRequest() {
            await super.computeSnippetsRequest();
            if (this.snippets) {
                const url = this.projectRequest?.readUrl();
                if (url) {
                    this.snippets.url = url;
                }
            }
        }
        renderUrlMeta() {
            return html ` ${this.renderHttpMethodSelector()} ${this.renderEnvironmentSelector()} ${this.renderUrlEditor()} `;
        }
        renderEnvironmentSelector() {
            const { environmentLabel: currentEnvironmentLabel, environments } = this;
            if (!environments?.length) {
                return nothing;
            }
            return html `
      <ui-dropdown-list
        verticalAlign="top"
        @select="${this.handleEnvironmentSelection}"
        class="environment-dropdown"
        closeOnOutsideClick
      >
        <ui-button color="text" class="button">
          ${currentEnvironmentLabel || 'No environment'}
          <ui-icon icon="arrowDropDown"></ui-icon>
        </ui-button>
        <ui-list slot="dropdown" role="menu">
          <ui-list-item
            role="menuitem"
            title="Selects the environment in the request's folder or inherited from a parent"
            >Inherited environment</ui-list-item
          >
          ${this.renderEnvironmentOptions(environments)}
        </ui-list>
      </ui-dropdown-list>
    `;
        }
        renderEnvironmentOptions(environments) {
            return environments.map((env) => this.renderEnvironmentItem(env));
        }
        renderEnvironmentItem(env) {
            const srv = env.getServer();
            const srvUri = srv?.readUri();
            const label = srvUri || 'Server not defined';
            // note, we don't disable items without server because it may still apply variables
            // from it.
            return html `
      <ui-list-item role="menuitem" data-key="${env.key}" lines="two">
        ${env.info.renderLabel}
        <p slot="supporting-text">${label}</p>
      </ui-list-item>
    `;
        }
        renderEmptyAuthorization() {
            return html `
      <div class="body-medium centered">
        This request will inherit authorization defined in an environment (if any).<br />
        Add an authorization to this request to override.
      </div>
    `;
        }
    };
})();
/**
 * An element that specializes in rendering an HTTP request that is defined on an HttpProject.
 *
 * When using this element set the `project` property to the currently opened
 * project and the `key` to the request to render.
 * The element will hook-up to the events to support project mutations.
 */
export default HttpProjectRequest;
//# sourceMappingURL=HttpProjectRequest.js.map