import { __decorate } from "tslib";
import { LitElement, html, nothing } from 'lit';
import { property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ErrorResponse } from '@api-client/core/build/browser.js';
import { statusTemplate } from '../http/HttpStatus.js';
import { RequestLogView } from '../http/RequestLog.js';
import '@github/relative-time-element';
import '../../define/http/http-request-log.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';
import '../../define/ui/ui-segmented-button.js';
import '../../define/ui/ui-segmented-button-set.js';
export var ProjectRunReportView;
(function (ProjectRunReportView) {
    ProjectRunReportView["summary"] = "summary";
    ProjectRunReportView["details"] = "details";
})(ProjectRunReportView || (ProjectRunReportView = {}));
/**
 * An element that renders the execution log of the project runner with the IProjectExecutionLog.
 */
export default class ProjectRunReport extends LitElement {
    constructor() {
        super(...arguments);
        this.view = ProjectRunReportView.summary;
    }
    willUpdate(cp) {
        super.updated(cp);
        if (cp.has('report')) {
            this.processReport();
        }
    }
    processReport() {
        const { report } = this;
        if (!report) {
            this.selectedIteration = undefined;
            this.selectedRequest = undefined;
            this.currentIteration = undefined;
            this.currentLog = undefined;
            return;
        }
        this.selectedIteration = 0;
        this.selectedRequest = 0;
        const [iteration] = report.iterations;
        this.currentIteration = iteration;
        this.currentLog = iteration && iteration.executed && iteration.executed[0];
    }
    handleIterationSelection(e) {
        const element = e.detail.item;
        const { index } = element.dataset;
        if (!index) {
            return;
        }
        const typed = Number(index);
        if (Number.isNaN(typed)) {
            return;
        }
        this.selectIteration(typed);
    }
    selectIteration(index) {
        const { report } = this;
        if (!report) {
            return;
        }
        const item = report.iterations[index];
        if (!item) {
            return;
        }
        this.selectedIteration = index;
        this.currentIteration = item;
        this.selectedRequest = 0;
        this.currentLog = item.executed && item.executed[0];
    }
    handleRequestSelection(e) {
        const element = e.detail.item;
        const { index } = element.dataset;
        if (!index) {
            return;
        }
        const typed = Number(index);
        if (Number.isNaN(typed)) {
            return;
        }
        this.selectRequest(typed);
    }
    selectRequest(index) {
        const { currentIteration } = this;
        if (!currentIteration) {
            return;
        }
        const item = currentIteration.executed[index];
        if (!item) {
            return;
        }
        this.selectedRequest = index;
        this.currentLog = item;
    }
    handleViewSelection(e) {
        if (!e.detail.selected) {
            return;
        }
        const button = e.detail.button;
        const view = button.dataset.value;
        if (view) {
            this.view = view;
        }
    }
    handleLinkClick(e) {
        const node = e.target;
        const { iterationIndex, requestIndex, target } = node.dataset;
        if (!requestIndex || !iterationIndex) {
            return;
        }
        const iteration = Number(iterationIndex);
        const request = Number(requestIndex);
        if (Number.isNaN(request) || Number.isNaN(iteration)) {
            return;
        }
        this.selectIteration(iteration);
        this.selectRequest(request);
        this.view = ProjectRunReportView.details;
        if (target) {
            this.selectLogView(target);
        }
    }
    handleLinkKeyDown(e) {
        if (['Enter', 'Space'].includes(e.code)) {
            this.handleLinkClick(e);
        }
    }
    async selectLogView(view) {
        await this.updateComplete;
        const node = this.shadowRoot?.querySelector('http-request-log');
        if (!node) {
            return;
        }
        node.view = view;
    }
    render() {
        const { report } = this;
        if (!report) {
            return html ``;
        }
        return html `
    ${this.renderHeader(report)}
    ${this.renderView()}
    `;
    }
    renderHeader(report) {
        return html `
    <div class="header">
      ${this.renderCurrentSelectors(report)}
      ${this.renderViewToggle()}
    </div>
    `;
    }
    renderCurrentSelectors(report) {
        if (this.view === ProjectRunReportView.summary) {
            return nothing;
        }
        const hasIterations = report.iterations.length > 1;
        return html `
    ${hasIterations ? this.renderInteractionsList(report.iterations) : nothing}
    ${this.renderRequestsList()}
    `;
    }
    renderViewToggle() {
        const { view } = this;
        return html `
    <div class="view-toggle">
      <ui-segmented-button-set @select="${this.handleViewSelection}">
        <ui-segmented-button 
          .selected="${view === ProjectRunReportView.summary}" 
          title="Shows summary of the run report" 
          data-value="summary"
        >Summary</ui-segmented-button>
        <ui-segmented-button 
          .selected="${view === ProjectRunReportView.details}" 
          title="Shows detailed response information for each request" 
          data-value="details"
        >Details</ui-segmented-button>
      </ui-segmented-button-set>
    </div>
    `;
    }
    renderInteractionsList(iterations) {
        const { selectedIteration = 0 } = this;
        const iteration = iterations[selectedIteration];
        const index = iteration ? iteration.index + 1 : 1;
        return html `
    <ui-dropdown-list
      verticalAlign="top"
      class="iterations-dropdown"
      closeOnOutsideClick
      @select="${this.handleIterationSelection}"
    >
      <ui-button type="tonal">
        <ui-icon slot="icon" icon="arrowDropDown"></ui-icon>
        Iteration #${index}
      </ui-button>
      <ui-list slot="dropdown" role="menu" aria-label="Iterations list">
        ${iterations.map(current => this.renderIterationOption(current.index))}
      </ui-list>
    </ui-dropdown-list>
    `;
    }
    renderIterationOption(index) {
        const classes = {
            'iteration-option': true,
            highlight: this.selectedIteration === index,
        };
        return html `
    <ui-list-item role="menuitem" data-index="${index}" class="${classMap(classes)}">
      Iteration #${index + 1}
    </ui-list-item>
    `;
    }
    renderRequestsList() {
        const { currentIteration, selectedRequest = 0 } = this;
        if (!currentIteration) {
            return this.renderEmptyRequestsList();
        }
        if (!currentIteration.executed || !currentIteration.executed.length) {
            return this.renderEmptyRequestsList();
        }
        const options = currentIteration.executed.map((item, index) => this.renderRequestsOption(item, index));
        const item = currentIteration.executed[selectedRequest];
        const title = item.request && item.request.url || `Request #${selectedRequest}`;
        return html `
    <ui-dropdown-list
      verticalAlign="top"
      class="history-dropdown"
      closeOnOutsideClick
      @select="${this.handleRequestSelection}"
    >
      <ui-button type="tonal" title="${title}">
        <ui-icon slot="icon" icon="arrowDropDown"></ui-icon>
        <span class="request-title-dropdown">${title}</span>
      </ui-button>
      <ui-list slot="dropdown" role="menu" aria-label="History list">
        ${options}
      </ui-list>
    </ui-dropdown-list>
    `;
    }
    renderEmptyRequestsList() {
        return html `
    <ui-button type="tonal" disabled>
      <ui-icon slot="icon" icon="arrowDropDown"></ui-icon>
      No requests
    </ui-button>
    `;
    }
    renderRequestsOption(item, index) {
        const title = item.request && item.request.url || `Request #${index}`;
        const error = !item.response || ErrorResponse.isErrorResponse(item.response);
        const classes = {
            'history-option': true,
            error,
            highlight: this.selectedRequest === index,
        };
        let status = 0;
        let statusText;
        let duration = 0;
        if (!error) {
            const typed = item.response;
            status = typed.status;
            statusText = typed.statusText;
            duration = typed.loadingTime;
        }
        return html `
    <ui-list-item lines="two" role="menuitem" data-index="${index}" class="${classMap(classes)}">
      <div class="history-label">
        <span class="label-value">${statusTemplate(status, statusText)} ${duration} ms</span>
      </div>
      <span slot="supporting-text">${title}</span>
    </ui-list-item>
    `;
    }
    renderView() {
        switch (this.view) {
            case ProjectRunReportView.details: return this.renderLog();
            case ProjectRunReportView.summary: return this.renderSummary();
            default: return html `<p>Invalid view selection.</p>`;
        }
    }
    renderLog() {
        const { currentLog } = this;
        return html `
    <div class="response">
      ${currentLog ? html `<http-request-log .httpLog="${currentLog}"></http-request-log>` : ''}
    </div>
    `;
    }
    renderSummary() {
        const { report } = this;
        if (!report) {
            return html `<p>Report is not set.</p>`;
        }
        const { iterations, ended } = report;
        const de = new Date(ended);
        return html `
    <div class="summary-header">
      Run ended <relative-time slot="supporting-text" datetime="${de.toISOString()}"></relative-time>
    </div>
    ${iterations.map(iteration => this.renderIterationSummary(iteration))}
    `;
    }
    renderIterationSummary(iteration) {
        const { error, executed, index } = iteration;
        return html `
    ${error ? this.renderIterationError() : this.renderIterationSummaryTable(index, executed)}
    `;
    }
    renderIterationError() {
        return html `
    <p class="iteration-error">The iteration was not executed due to an error.</p>
    `;
    }
    renderIterationSummaryTable(iterationIndex, executed) {
        const failedIndex = [];
        executed.forEach((item, index) => {
            const { assertions = [] } = item;
            const hasFailed = assertions.find(i => !i.ok);
            if (hasFailed) {
                failedIndex.push(`#${index + 1}`);
            }
        });
        const formatter = new Intl.ListFormat(undefined, { style: 'long', type: 'conjunction' });
        return html `
    <table class="execution-table">
      <caption>Iteration #${iterationIndex + 1}. Failed requests: ${failedIndex.length ? formatter.format(failedIndex) : 'none'}.</caption>
      <thead>
        <tr>
          <th scope="col" class="request">HTTP request</th>
          <th scope="col" class="status">Status</th>
          <th scope="col" class="time">Time</th>
          <th scope="col" class="assertions">Assertions</th>
        </tr>
      </thead>
      <tbody>
        ${executed.map((item, requestIndex) => this.renderSummaryTableRow(item, iterationIndex, requestIndex))}
      </tbody>
    </table>
    `;
    }
    renderSummaryTableRow(item, iterationIndex, requestIndex) {
        const { assertions = [], request, response } = item;
        if (!request) {
            return html `
      <tr>
        <td colspan="3">The request was not executed (missing request info)</td>
      </tr>
      `;
        }
        const error = !item.response || ErrorResponse.isErrorResponse(item.response);
        let status;
        let duration = 0;
        if (error) {
            status = html `Errored`;
        }
        else if (response) {
            status = statusTemplate(response.status, response.statusText);
            duration = response.loadingTime;
        }
        else {
            status = html `Unknown`;
        }
        const successAssertions = (item.assertions || []).filter(i => i.ok);
        const hasFailed = assertions.length - successAssertions.length !== 0;
        return html `
    <tr>
      <td class="request">
        <span class="http-label pill" data-method="${(request.method || 'get').toLowerCase()}">${request.method}</span>
        <span 
          class="link" 
          title="Open details" 
          data-iteration-index="${iterationIndex}" 
          data-request-index="${requestIndex}"
          @click="${this.handleLinkClick}"
          @keydown="${this.handleLinkKeyDown}"
          tabindex="0"
        >${request.url}</span>
      </td>
      <td class="status">${status}</td>
      <td class="time">${duration}ms</td>
      <td class="assertions">
        <span
          class="link"
          title="Open assertion details"
          data-iteration-index="${iterationIndex}" 
          data-request-index="${requestIndex}"
          data-target="${RequestLogView.assertions}"
          @click="${this.handleLinkClick}"
          @keydown="${this.handleLinkKeyDown}"
          tabindex="0"
        >${successAssertions.length}/${assertions.length}</span>
        ${hasFailed ? html `<div class="badge small"></div>` : ''}
      </td>
    </tr>
    `;
    }
}
__decorate([
    property({ type: Object })
], ProjectRunReport.prototype, "report", void 0);
__decorate([
    state()
], ProjectRunReport.prototype, "selectedIteration", void 0);
__decorate([
    state()
], ProjectRunReport.prototype, "selectedRequest", void 0);
__decorate([
    state()
], ProjectRunReport.prototype, "currentIteration", void 0);
__decorate([
    state()
], ProjectRunReport.prototype, "currentLog", void 0);
__decorate([
    state()
], ProjectRunReport.prototype, "view", void 0);
//# sourceMappingURL=ProjectRunReport.js.map