import { __decorate } from "tslib";
import { html, nothing } from 'lit';
import { property, state } from 'lit/decorators.js';
import { Events as CoreEvents, HttpHistoryKind, HttpProjectKind, HeadersArray, RequestAuthorization, RequestConfig, } from '@api-client/core/build/browser.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 '../../define/ui/ui-icon.js';
import '../../define/ui/ui-button.js';
import '../../define/ui/ui-dropdown-list.js';
import '../../define/ui/ui-list.js';
import '../../define/ui/ui-list-item.js';
function stopEvent(e) {
    e.stopPropagation();
}
/**
 * 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 class HttpProjectRequest extends RequestEditor {
    constructor() {
        super();
        // 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 (e) {
            // ...
        }
        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: '',
            midnight: midnightTimestamp(),
            key: '',
            space: '', // will be filled by the bindings.
        };
        Events.Store.History.create(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 type="text">
        ${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>
    `;
    }
}
__decorate([
    property({ type: Object })
], HttpProjectRequest.prototype, "sharedVariables", void 0);
__decorate([
    property({ type: Object })
], HttpProjectRequest.prototype, "project", void 0);
__decorate([
    property({ type: String, reflect: true })
], HttpProjectRequest.prototype, "key", void 0);
__decorate([
    property({ type: Object })
], HttpProjectRequest.prototype, "appInfo", void 0);
__decorate([
    state()
], HttpProjectRequest.prototype, "environments", void 0);
__decorate([
    state()
], HttpProjectRequest.prototype, "environmentLabel", void 0);
__decorate([
    property({ type: Boolean })
], HttpProjectRequest.prototype, "useNetStore", void 0);
//# sourceMappingURL=HttpProjectRequest.js.map