import { __esDecorate, __runInitializers } from "tslib";
import { html, nothing } from 'lit';
import { property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { Kind as HttpProjectKind } from '@api-client/core/models/HttpProject.js';
import { Events as CoreEvents } from '@api-client/core/events/Events.js';
import ApiElement from '../ApiElement.js';
import '@github/relative-time-element';
import '../../define/http-project/project-run-report.js';
import '../../md/checkbox/ui-checkbox.js';
import '../../md/text-field/ui-filled-text-field.js';
import '../../md/button/ui-button.js';
import '../../md/progress/ui-progress.js';
import '../../md/icons/ui-icon.js';
import '../../md/dropdown-list/ui-dropdown-list.js';
import '../../md/list/ui-list.js';
import '../../md/list/ui-list-item.js';
let ProjectRunner = (() => {
    let _classSuper = ApiElement;
    let _sharedVariables_decorators;
    let _sharedVariables_initializers = [];
    let _sharedVariables_extraInitializers = [];
    let _project_decorators;
    let _project_initializers = [];
    let _project_extraInitializers = [];
    let _appInfo_decorators;
    let _appInfo_initializers = [];
    let _appInfo_extraInitializers = [];
    let _folder_decorators;
    let _folder_initializers = [];
    let _folder_extraInitializers = [];
    let _root_decorators;
    let _root_initializers = [];
    let _root_extraInitializers = [];
    let _running_decorators;
    let _running_initializers = [];
    let _running_extraInitializers = [];
    let _querying_decorators;
    let _querying_initializers = [];
    let _querying_extraInitializers = [];
    let _config_decorators;
    let _config_initializers = [];
    let _config_extraInitializers = [];
    let _lastError_decorators;
    let _lastError_initializers = [];
    let _lastError_extraInitializers = [];
    let _renderedReport_decorators;
    let _renderedReport_initializers = [];
    let _renderedReport_extraInitializers = [];
    return class ProjectRunner 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 })];
            _appInfo_decorators = [property({ type: Object })];
            _folder_decorators = [property({ type: String, reflect: true })];
            _root_decorators = [state()];
            _running_decorators = [state()];
            _querying_decorators = [state()];
            _config_decorators = [property({ type: Object })];
            _lastError_decorators = [state()];
            _renderedReport_decorators = [state()];
            __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, _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, _folder_decorators, { kind: "accessor", name: "folder", static: false, private: false, access: { has: obj => "folder" in obj, get: obj => obj.folder, set: (obj, value) => { obj.folder = value; } }, metadata: _metadata }, _folder_initializers, _folder_extraInitializers);
            __esDecorate(this, null, _root_decorators, { kind: "accessor", name: "root", static: false, private: false, access: { has: obj => "root" in obj, get: obj => obj.root, set: (obj, value) => { obj.root = value; } }, metadata: _metadata }, _root_initializers, _root_extraInitializers);
            __esDecorate(this, null, _running_decorators, { kind: "accessor", name: "running", static: false, private: false, access: { has: obj => "running" in obj, get: obj => obj.running, set: (obj, value) => { obj.running = value; } }, metadata: _metadata }, _running_initializers, _running_extraInitializers);
            __esDecorate(this, null, _querying_decorators, { kind: "accessor", name: "querying", static: false, private: false, access: { has: obj => "querying" in obj, get: obj => obj.querying, set: (obj, value) => { obj.querying = value; } }, metadata: _metadata }, _querying_initializers, _querying_extraInitializers);
            __esDecorate(this, null, _config_decorators, { kind: "accessor", name: "config", static: false, private: false, access: { has: obj => "config" in obj, get: obj => obj.config, set: (obj, value) => { obj.config = value; } }, metadata: _metadata }, _config_initializers, _config_extraInitializers);
            __esDecorate(this, null, _lastError_decorators, { kind: "accessor", name: "lastError", static: false, private: false, access: { has: obj => "lastError" in obj, get: obj => obj.lastError, set: (obj, value) => { obj.lastError = value; } }, metadata: _metadata }, _lastError_initializers, _lastError_extraInitializers);
            __esDecorate(this, null, _renderedReport_decorators, { kind: "accessor", name: "renderedReport", static: false, private: false, access: { has: obj => "renderedReport" in obj, get: obj => obj.renderedReport, set: (obj, value) => { obj.renderedReport = value; } }, metadata: _metadata }, _renderedReport_initializers, _renderedReport_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 instance of the current project.
         */
        get project() { return this.#project_accessor_storage; }
        set project(value) { this.#project_accessor_storage = value; }
        #appInfo_accessor_storage = (__runInitializers(this, _project_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; }
        #folder_accessor_storage = (__runInitializers(this, _appInfo_extraInitializers), __runInitializers(this, _folder_initializers, void 0));
        /**
         * The key of the folder to render the runner for.
         * When not set, it renders the runner for the project.
         * @attribute
         */
        get folder() { return this.#folder_accessor_storage; }
        set folder(value) { this.#folder_accessor_storage = value; }
        #root_accessor_storage = (__runInitializers(this, _folder_extraInitializers), __runInitializers(this, _root_initializers, void 0));
        /**
         * The object we operate on.
         */
        get root() { return this.#root_accessor_storage; }
        set root(value) { this.#root_accessor_storage = value; }
        #running_accessor_storage = (__runInitializers(this, _root_extraInitializers), __runInitializers(this, _running_initializers, void 0));
        /**
         * Whether the element is currently running the project execution.
         */
        get running() { return this.#running_accessor_storage; }
        set running(value) { this.#running_accessor_storage = value; }
        #querying_accessor_storage = (__runInitializers(this, _running_extraInitializers), __runInitializers(this, _querying_initializers, void 0));
        /**
         * Whether the element is currently querying for the history data.
         */
        get querying() { return this.#querying_accessor_storage; }
        set querying(value) { this.#querying_accessor_storage = value; }
        /**
         * The page cursor for pagination.
         */
        pageCursor = __runInitializers(this, _querying_extraInitializers);
        #config_accessor_storage = __runInitializers(this, _config_initializers, void 0);
        /**
         * The run configuration.
         */
        get config() { return this.#config_accessor_storage; }
        set config(value) { this.#config_accessor_storage = value; }
        #lastError_accessor_storage = (__runInitializers(this, _config_extraInitializers), __runInitializers(this, _lastError_initializers, void 0));
        get lastError() { return this.#lastError_accessor_storage; }
        set lastError(value) { this.#lastError_accessor_storage = value; }
        history = (__runInitializers(this, _lastError_extraInitializers), []);
        queryPageDebouncer;
        debounceTimeout = 100;
        /**
         * The key of the currently rendered report.
         */
        selectedReport;
        #renderedReport_accessor_storage = __runInitializers(this, _renderedReport_initializers, void 0);
        /**
         * The currently rendered report.
         */
        get renderedReport() { return this.#renderedReport_accessor_storage; }
        set renderedReport(value) { this.#renderedReport_accessor_storage = value; }
        willUpdate(cp) {
            super.willUpdate(cp);
            if (cp.has('project') || cp.has('folder')) {
                this.setupRoot();
            }
        }
        setupRoot() {
            const { project, folder } = this;
            if (!project) {
                this.root = undefined;
                return;
            }
            if (!folder) {
                this.root = project;
            }
            else {
                this.root = project.findFolder(folder);
            }
            this.resetHistory();
            this.queryPageDebounce();
        }
        handleRun() {
            this.execute();
        }
        /**
         * Executes the current configuration.
         */
        async execute() {
            this.lastError = undefined;
            const { config = {}, folder, project } = this;
            if (!project) {
                return;
            }
            if (folder) {
                config.parent = folder;
            }
            // Note, we intentionally don't add shared variables.
            // Project / folder execution should be contained and can only leak
            // out the variables to the rest of the app, not in.
            // if (sharedVariables && !config.variables) {
            //   config.variables = sharedVariables;
            // }
            const init = {
                kind: HttpProjectKind,
                project: project.toJSON(),
                options: config,
            };
            this.running = true;
            try {
                const result = await CoreEvents.Transport.Core.httpProject(init, this);
                if (!result) {
                    this.lastError = 'The project execution event was not handled.';
                }
                else {
                    this.mergeExecutedVariables(result.result);
                    this.createHistory(result.result);
                }
            }
            catch (e) {
                this.lastError = e.message;
            }
            this.running = false;
        }
        mergeExecutedVariables(result) {
            const { sharedVariables } = this;
            if (!sharedVariables) {
                return;
            }
            result.iterations.forEach((iteration) => {
                const { variables } = iteration;
                if (!variables) {
                    return;
                }
                Object.keys(variables).forEach((key) => {
                    sharedVariables[key] = variables[key];
                });
            });
        }
        async createHistory(result) {
            const { appInfo, project } = this;
            if (!appInfo) {
                throw new Error(`The appInfo is not set on ${this.localName}`);
            }
            if (!project) {
                return;
            }
            throw new Error(`Not yet implemented: ${result}`);
            // await Events.Store.ProjectRuns.add({
            //   ...result,
            //   app: appInfo.code,
            //   project: project.key,
            //   key: '',
            //   kind: ProjectExecutionKind,
            //   midnight: 0,
            //   parent: this.folder,
            // })
        }
        resetHistory() {
            this.querying = false;
            this.pageCursor = undefined;
            this.history = [];
            if (this.queryPageDebouncer) {
                clearTimeout(this.queryPageDebouncer);
                this.queryPageDebouncer = undefined;
            }
        }
        queryPageDebounce() {
            if (this.queryPageDebouncer) {
                return;
            }
            this.queryPageDebouncer = setTimeout(() => {
                this.queryPageDebouncer = undefined;
                this.queryPage();
            }, this.debounceTimeout);
        }
        async queryPage() {
            const { project, appInfo, folder, pageCursor } = this;
            if (this.querying || !project) {
                return;
            }
            this.querying = true;
            const opts = {
                organization: '',
                project: project.key,
            };
            if (appInfo) {
                opts.app = appInfo.code;
            }
            if (folder) {
                opts.parent = folder;
            }
            if (pageCursor) {
                opts.cursor = pageCursor;
            }
            try {
                throw new Error(`Not yet implemented: ${opts}`);
                // const result = await Events.Store.ProjectRuns.list(opts, this)
                // if (!result) {
                //   throw new Error(`Project runs query not handled by the store.`)
                // }
                // const { items, cursor } = result
                // if (items.length) {
                //   if (cursor) {
                //     this.pageCursor = cursor
                //   }
                //   this.history = this.history.concat(items)
                //   this.history.sort(this.historySort)
                //   if (!this.selectedReport) {
                //     const [last] = this.history
                //     this.selectHistory(last.key)
                //   }
                //   this.requestUpdate()
                // }
            }
            catch (e) {
                // eslint-disable-next-line no-console
                console.warn(e);
            }
            finally {
                this.querying = false;
            }
        }
        historySort(a, b) {
            return b.ended - a.ended;
        }
        setRecursive(value) {
            const { config = {} } = this;
            config.recursive = value;
            this.config = config;
            this.notifyChange();
        }
        setParallel(value) {
            const { config = {} } = this;
            config.parallel = value;
            this.config = config;
            this.notifyChange();
        }
        setIterations(value) {
            const { config = {} } = this;
            config.iterations = value;
            this.config = config;
            this.notifyChange();
        }
        setIterationDelay(value) {
            const { config = {} } = this;
            config.iterationDelay = value;
            this.config = config;
            this.notifyChange();
        }
        handleRecursiveChecked(e) {
            const input = e.target;
            this.setRecursive(!!input.checked);
        }
        handleParallelChecked(e) {
            const input = e.target;
            this.setParallel(!!input.checked);
        }
        handleIterationsChange(e) {
            const input = e.target;
            this.setIterations(input.valueAsNumber);
            input.checkValidity();
        }
        handleIterationDelayChange(e) {
            const input = e.target;
            this.setIterationDelay(input.valueAsNumber);
            input.checkValidity();
        }
        handleHistorySelection(e) {
            const element = e.detail.item;
            const { key } = element.dataset;
            if (!key) {
                return;
            }
            this.selectHistory(key);
        }
        selectHistory(key) {
            this.selectedReport = key;
            const { history } = this;
            const report = history.find((i) => i.key === key);
            if (report) {
                this.renderedReport = report;
            }
            else {
                this.renderedReport = undefined;
            }
        }
        render() {
            const { root } = this;
            if (!root) {
                return html ``;
            }
            return html `
      <section id="config">
        <div class="header title-large section-title">Project runner for ${root.info.renderLabel}</div>
        <form name="run-config" class="run-config surface1">
          <div class="section-title title-medium">Run configuration</div>
          ${this.renderRecursiveOption()} ${this.renderParallelOption()} ${this.renderIterationOption()}
          ${this.renderIterationDelayOption()} ${this.renderSubmit()}
        </form>
        ${this.renderError()} ${this.renderLoader()} ${this.renderReport()}
      </section>
    `;
        }
        renderRecursiveOption() {
            const { config = {} } = this;
            const value = typeof config.recursive === 'boolean' ? config.recursive : false;
            return html `
      <div class="form-row">
        <ui-checkbox
          id="recursive"
          .checked="${value}"
          name="recursive"
          aria-labelledby="recursiveLabel"
          aria-describedby="recursiveDescription"
          @change="${this.handleRecursiveChecked}"
        ></ui-checkbox>
        <label class="label-large" for="recursive" id="recursiveLabel"> Recursive </label>
        <p class="body-medium" id="recursiveDescription">
          Runs all requests from the current folder and its sub-folders
        </p>
      </div>
    `;
        }
        renderParallelOption() {
            const { config = {} } = this;
            const value = typeof config.parallel === 'boolean' ? config.parallel : false;
            return html `
      <div class="form-row">
        <ui-checkbox
          id="parallel"
          .checked="${value}"
          name="parallel"
          aria-labelledby="parallelLabel"
          aria-describedby="parallelDescription"
          @change="${this.handleParallelChecked}"
        ></ui-checkbox>
        <label class="label-large" for="parallel" id="parallelLabel"> Parallel </label>
        <p class="body-medium" id="parallelDescription">
          Runs each iteration in parallel. The number of actual execution depends on the number of cores on your device.
          This is ignored when number of iterations is 1.
        </p>
      </div>
    `;
        }
        renderIterationOption() {
            const { config = {} } = this;
            const value = typeof config.iterations === 'number' ? config.iterations : 1;
            return html `
      <div class="form-row">
        <ui-filled-text-field
          required
          label="Iterations"
          aria-describedby="iterationsDescription"
          name="iterations"
          type="number"
          min="1"
          step="1"
          .value="${String(value)}"
          @change="${this.handleIterationsChange}"
        ></ui-filled-text-field>
        <p class="body-medium" id="iterationsDescription">The number of times the execution should be repeated.</p>
      </div>
    `;
        }
        renderIterationDelayOption() {
            const { config = {} } = this;
            const value = typeof config.iterationDelay === 'number' ? config.iterationDelay : 0;
            return html `
      <div class="form-row">
        <ui-filled-text-field
          required
          label="Iteration delay"
          aria-describedby="iterationDelayDescription"
          name="iterationDelay"
          type="number"
          min="0"
          step="1"
          .value="${String(value)}"
          @change="${this.handleIterationDelayChange}"
        ></ui-filled-text-field>
        <p class="body-medium" id="iterationDelayDescription">
          The number of milliseconds to wait between each iteration.
        </p>
      </div>
    `;
        }
        renderSubmit() {
            return html `
      <div class="submit-row">
        <ui-button color="filled" @click="${this.handleRun}" ?disabled="${this.running}">Run</ui-button>
      </div>
    `;
        }
        renderLoader() {
            if (!this.running) {
                return '';
            }
            return html ` <ui-progress indeterminate></ui-progress> `;
        }
        renderError() {
            const { lastError } = this;
            if (!lastError) {
                return '';
            }
            return html `<div class="error on-error-text body-large last-error">${lastError}</div>`;
        }
        renderReport() {
            const { renderedReport, history } = this;
            if (!history.length) {
                return nothing;
            }
            return html `
      <section aria-label="Latest report" class="report surface1">
        <div class="section-title title-medium">Run reports</div>
        ${this.renderHistorySelector()}
        <project-run-report .report="${renderedReport}"></project-run-report>
      </section>
    `;
        }
        renderHistorySelector() {
            const { history } = this;
            const disabled = !history.length;
            const selected = history.find((i) => i.key === this.selectedReport);
            return html `
      <div class="history-selector">
        <ui-dropdown-list
          verticalAlign="top"
          class="history-dropdown"
          closeOnOutsideClick
          @select="${this.handleHistorySelection}"
        >
          <ui-button color="tonal" ?disabled="${disabled}">
            <ui-icon slot="icon" icon="arrowDropDown"></ui-icon>
            ${selected
                ? html `<relative-time datetime="${new Date(selected.ended).toISOString()}"></relative-time>`
                : 'History'}
          </ui-button>
          <ui-list slot="dropdown" role="menu" aria-label="History list">
            ${history.map((current) => this.renderHistoryOption(current))}
          </ui-list>
        </ui-dropdown-list>
      </div>
    `;
        }
        renderHistoryOption(item) {
            const { ended, key } = item;
            const classes = {
                'history-option': true,
                'highlight': this.selectedReport === key,
            };
            const de = new Date(ended);
            return html `
      <ui-list-item role="menuitem" data-key="${key}" class="${classMap(classes)}">
        <relative-time datetime="${de.toISOString()}"></relative-time>
      </ui-list-item>
    `;
        }
        constructor() {
            super(...arguments);
            __runInitializers(this, _renderedReport_extraInitializers);
        }
    };
})();
/**
 * @fires change - When the configuration of the runner change.
 */
export default ProjectRunner;
//# sourceMappingURL=ProjectRunner.js.map