import { __esDecorate, __runInitializers } from "tslib";
import { html, nothing } from 'lit';
import { RequestLog as CoreRequestLog } from '@api-client/core/models/RequestLog.js';
import { ErrorResponse } from '@api-client/core/models/ErrorResponse.js';
import { Headers } from '@api-client/core/lib/headers/Headers.js';
import { property, state } from 'lit/decorators.js';
import { statusTemplate } from './HttpStatus.js';
import ApiElement from '../ApiElement.js';
import '../../define/http/http-log-headers.js';
import '../../define/http/http-log-body.js';
import '../../define/http/http-log-timings.js';
import '../../md/tabs/ui-tab.js';
import '../../md/tabs/ui-tabs.js';
import '../../md/divider/ui-divider.js';
export var RequestLogView;
(function (RequestLogView) {
    RequestLogView["headers"] = "headers";
    RequestLogView["payload"] = "payload";
    RequestLogView["preview"] = "preview";
    RequestLogView["response"] = "response";
    RequestLogView["timings"] = "timings";
    RequestLogView["redirects"] = "redirects";
    RequestLogView["assertions"] = "assertions";
})(RequestLogView || (RequestLogView = {}));
let RequestLog = (() => {
    let _classSuper = ApiElement;
    let _instanceExtraInitializers = [];
    let _set_httpLog_decorators;
    let _view_decorators;
    let _view_initializers = [];
    let _view_extraInitializers = [];
    let _isErrorResponse_decorators;
    let _isErrorResponse_initializers = [];
    let _isErrorResponse_extraInitializers = [];
    let _timingsData_decorators;
    let _timingsData_initializers = [];
    let _timingsData_extraInitializers = [];
    let _redirectsData_decorators;
    let _redirectsData_initializers = [];
    let _redirectsData_extraInitializers = [];
    return class RequestLog extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _set_httpLog_decorators = [property({ type: Object })];
            _view_decorators = [property({ type: String })];
            _isErrorResponse_decorators = [state()];
            _timingsData_decorators = [state()];
            _redirectsData_decorators = [state()];
            __esDecorate(this, null, _set_httpLog_decorators, { kind: "setter", name: "httpLog", static: false, private: false, access: { has: obj => "httpLog" in obj, set: (obj, value) => { obj.httpLog = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _view_decorators, { kind: "accessor", name: "view", static: false, private: false, access: { has: obj => "view" in obj, get: obj => obj.view, set: (obj, value) => { obj.view = value; } }, metadata: _metadata }, _view_initializers, _view_extraInitializers);
            __esDecorate(this, null, _isErrorResponse_decorators, { kind: "accessor", name: "isErrorResponse", static: false, private: false, access: { has: obj => "isErrorResponse" in obj, get: obj => obj.isErrorResponse, set: (obj, value) => { obj.isErrorResponse = value; } }, metadata: _metadata }, _isErrorResponse_initializers, _isErrorResponse_extraInitializers);
            __esDecorate(this, null, _timingsData_decorators, { kind: "accessor", name: "timingsData", static: false, private: false, access: { has: obj => "timingsData" in obj, get: obj => obj.timingsData, set: (obj, value) => { obj.timingsData = value; } }, metadata: _metadata }, _timingsData_initializers, _timingsData_extraInitializers);
            __esDecorate(this, null, _redirectsData_decorators, { kind: "accessor", name: "redirectsData", static: false, private: false, access: { has: obj => "redirectsData" in obj, get: obj => obj.redirectsData, set: (obj, value) => { obj.redirectsData = value; } }, metadata: _metadata }, _redirectsData_initializers, _redirectsData_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        httpLogInternal = __runInitializers(this, _instanceExtraInitializers);
        /**
         * This property is set when the `httpLog` is set.
         * It always represent an instance of the `RequestLog` (or undefined) regardless of the input format.
         */
        effectiveLog;
        /**
         * The request log to render. When not set it renders nothing.
         */
        get httpLog() {
            return this.httpLogInternal;
        }
        set httpLog(value) {
            const old = this.httpLogInternal;
            if (old === value) {
                return;
            }
            this.httpLogInternal = value;
            if (value) {
                if (typeof value.toJSON === 'function') {
                    this.effectiveLog = value;
                }
                else {
                    this.effectiveLog = new CoreRequestLog(value);
                }
            }
            else {
                this.effectiveLog = undefined;
            }
            this.processPayload();
            this.requestUpdate();
        }
        #view_accessor_storage = __runInitializers(this, _view_initializers, RequestLogView.headers
        /**
         * Returns `true` when the request has a payload message.
         */
        );
        /**
         * Currently rendered view.
         * @attribute
         */
        get view() { return this.#view_accessor_storage; }
        set view(value) { this.#view_accessor_storage = value; }
        /**
         * Returns `true` when the request has a payload message.
         */
        get hasRequestPayload() {
            const { effectiveLog } = this;
            if (!effectiveLog) {
                return false;
            }
            const { request } = effectiveLog;
            if (!request) {
                return false;
            }
            if (['get', 'head'].includes(request.method.toLowerCase())) {
                return false;
            }
            return !!request.payload;
        }
        /**
         * Returns `true` when the response has a payload message.
         */
        get hasResponsePayload() {
            const { effectiveLog } = this;
            if (!effectiveLog) {
                return false;
            }
            const { response } = effectiveLog;
            if (!response) {
                return false;
            }
            return !!response.payload;
        }
        get hasResponse() {
            const { effectiveLog } = this;
            if (!effectiveLog) {
                return false;
            }
            const { response } = effectiveLog;
            return !!response;
        }
        #isErrorResponse_accessor_storage = (__runInitializers(this, _view_extraInitializers), __runInitializers(this, _isErrorResponse_initializers, false));
        get isErrorResponse() { return this.#isErrorResponse_accessor_storage; }
        set isErrorResponse(value) { this.#isErrorResponse_accessor_storage = value; }
        #timingsData_accessor_storage = (__runInitializers(this, _isErrorResponse_extraInitializers), __runInitializers(this, _timingsData_initializers, void 0));
        get timingsData() { return this.#timingsData_accessor_storage; }
        set timingsData(value) { this.#timingsData_accessor_storage = value; }
        #redirectsData_accessor_storage = (__runInitializers(this, _timingsData_extraInitializers), __runInitializers(this, _redirectsData_initializers, void 0));
        get redirectsData() { return this.#redirectsData_accessor_storage; }
        set redirectsData(value) { this.#redirectsData_accessor_storage = value; }
        /**
         * Reads the payload to the original format for both the request and the response.
         */
        async processPayload() {
            const { effectiveLog } = this;
            if (!effectiveLog) {
                this.isErrorResponse = false;
                this.timingsData = undefined;
                this.redirectsData = undefined;
                return;
            }
            const { response } = effectiveLog;
            if (!response) {
                this.isErrorResponse = false;
                this.timingsData = undefined;
                this.redirectsData = undefined;
            }
            else {
                this.isErrorResponse = ErrorResponse.isErrorResponse(response);
                // computes list of redirects.
                if (!this.isErrorResponse) {
                    const r = response;
                    const timings = [];
                    const redirects = [];
                    if (Array.isArray(effectiveLog.redirects)) {
                        effectiveLog.redirects.forEach((rdr) => {
                            redirects.push(rdr);
                            if (rdr.timings) {
                                timings.push(rdr.timings);
                            }
                        });
                    }
                    if (r.timings) {
                        timings.push(r.timings);
                    }
                    this.timingsData = timings;
                    this.redirectsData = redirects;
                }
            }
        }
        handleViewSelect(e) {
            const key = e.detail.item.getAttribute('aria-controls');
            if (!key) {
                return;
            }
            this.view = key;
        }
        render() {
            const { effectiveLog } = this;
            return html ` ${this.renderTabs(effectiveLog)} ${this.renderContent(effectiveLog)} `;
        }
        renderTabs(effectiveLog) {
            const { view: s = 'headers' } = this;
            return html `
      <ui-tabs @select="${this.handleViewSelect}">
        <ui-tab
          .selected="${s === 'headers'}"
          aria-controls="headers"
          id="headers-tab"
          title="Request and response header"
          >Headers</ui-tab
        >
        <ui-tab
          ?hidden="${!this.hasRequestPayload}"
          .selected="${s === 'payload'}"
          aria-controls="payload"
          id="payload-tab"
          title="Request payload set to server"
          >Payload</ui-tab
        >
        <ui-tab
          ?hidden="${!this.hasResponsePayload}"
          .selected="${s === 'preview'}"
          aria-controls="preview"
          id="preview-tab"
          title="Formatted view of the response"
          >Preview</ui-tab
        >
        <ui-tab
          .selected="${s === 'response'}"
          aria-controls="response"
          id="response-tab"
          title="Unformatted view of the response"
          >Response</ui-tab
        >
        <ui-tab .selected="${s === 'timings'}" aria-controls="timings" id="timings-tab" title="Request detailed timings"
          >Timings</ui-tab
        >
        <ui-tab
          .selected="${s === 'redirects'}"
          aria-controls="redirects"
          id="redirects-tab"
          title="Detailed redirect information"
          >Redirects</ui-tab
        >
        <ui-tab
          .selected="${s === 'assertions'}"
          aria-controls="assertions"
          id="assertions-tab"
          title="HTTP assertions result"
          >Assertions ${this.renderAssertionsBadge(effectiveLog)}</ui-tab
        >
      </ui-tabs>
    `;
        }
        renderAssertionsBadge(effectiveLog) {
            if (!effectiveLog) {
                return nothing;
            }
            const { assertions = [] } = effectiveLog;
            const failed = assertions.filter((i) => !i.ok);
            if (!failed.length) {
                return nothing;
            }
            return html ` <span class="badge large-label tab">${failed.length}</span> `;
        }
        renderContent(effectiveLog) {
            const { view = RequestLogView.headers } = this;
            if (!effectiveLog) {
                return html `<div class="empty-info">No data available.</div>`;
            }
            let tpl;
            switch (view) {
                case RequestLogView.payload:
                    tpl = this.renderPayload(effectiveLog);
                    break;
                case RequestLogView.preview:
                    tpl = this.renderPreview(effectiveLog);
                    break;
                case RequestLogView.response:
                    tpl = this.renderResponse(effectiveLog);
                    break;
                case RequestLogView.timings:
                    tpl = this.renderTimings();
                    break;
                case RequestLogView.redirects:
                    tpl = this.renderRedirects();
                    break;
                case RequestLogView.assertions:
                    tpl = this.renderAssertions(effectiveLog);
                    break;
                default:
                    tpl = this.renderHeaders(effectiveLog);
            }
            return tpl;
        }
        /**
         * Renders basic information about the request:
         * - request method & URL
         * - request headers
         * - response headers
         */
        renderHeaders(info) {
            return html `
      <http-log-headers
        .httpLog="${info}"
        role="tabpanel"
        aria-labelledby="headers-tab"
        id="headers"
      ></http-log-headers>
    `;
        }
        /**
         * @returns The template for the "raw" response body view.
         */
        renderPayload(info) {
            if (!info) {
                return html ``;
            }
            const { request } = info;
            if (!request) {
                return this._noDataTemplate('payload-tab', 'payload');
            }
            const parser = new Headers(request.headers);
            const mime = parser.get('content-type');
            return html `
      <http-log-body
        .payload="${request.payload}"
        .contentType="${mime}"
        role="tabpanel"
        aria-labelledby="payload-tab"
        id="payload"
      ></http-log-body>
    `;
        }
        /**
         * @returns The template for the parsed response body view.
         */
        renderPreview(info) {
            if (!info) {
                return html ``;
            }
            const { response } = info;
            if (!response) {
                return html `<p aria-labelledby="preview-tab" id="preview" role="tabpanel">No response data</p>`;
            }
            const parser = new Headers(response.headers);
            const mime = parser.get('content-type');
            return html `
      <http-log-body
        aria-labelledby="preview-tab"
        id="preview"
        .payload="${response.payload}"
        .contentType="${mime}"
        role="tabpanel"
      ></http-log-body>
    `;
        }
        renderResponse(info) {
            if (!info) {
                return html ``;
            }
            const { response } = info;
            if (!response) {
                return this._noDataTemplate('response-tab', 'response');
            }
            const parser = new Headers(response.headers);
            const mime = parser.get('content-type');
            return html `
      <http-log-body
        aria-labelledby="response-tab"
        id="response"
        .payload="${response.payload}"
        .contentType="${mime}"
        raw
        role="tabpanel"
      ></http-log-body>
    `;
        }
        renderTimings() {
            const { timingsData } = this;
            if (!timingsData || !timingsData.length) {
                return this._noDataTemplate('timings-tab', 'timings');
            }
            return html `<http-log-timings
      aria-labelledby="timings-tab"
      id="timings"
      .timings="${timingsData}"
      role="tabpanel"
    ></http-log-timings>`;
        }
        renderRedirects() {
            const { redirectsData } = this;
            if (!redirectsData || !redirectsData.length) {
                return this._noDataTemplate('redirects-tab', 'redirects');
            }
            return html `
      <div role="tabpanel" aria-labelledby="redirects-tab" id="redirects">
        ${redirectsData.map((item, index) => this.renderRedirect(item, index))}
      </div>
    `;
        }
        renderRedirect(item, index) {
            const { url, response } = item;
            if (!response) {
                return html `
        <div class="status-row">
          <div class="status-label text">#<span>${index + 1}</span></div>
          <div class="redirect-value">This redirect has no response data</div>
        </div>
      `;
            }
            const headers = new Headers(response.headers);
            const mime = headers.get('content-type');
            return html `
      <div class="status-row">
        <div class="status-label text">#<span>${index + 1}</span></div>
        <div class="redirect-value">
          <div class="redirect-code">${statusTemplate(response.status, response.statusText)}</div>
          <div class="redirect-location">
            <a href="${url}" class="auto-link">${url}</a>
          </div>
          ${this.renderHeadersRaw(headers)}
          ${response.payload
                ? html `<http-log-body
                .payload="${response.payload}"
                .contentType="${mime}"
                role="tabpanel"
              ></http-log-body>`
                : ''}
        </div>
      </div>
    `;
        }
        renderHeadersRaw(header) {
            const templates = [];
            header.forEach((value, name) => {
                templates.push(html `
        <li>
          <span class="header-name">${name}</span>
          <span class="header-value">${value}</span>
        </li>
      `);
            });
            if (!templates.length) {
                return '';
            }
            return html `
      <ul class="headers">
        ${templates}
      </ul>
    `;
        }
        _noDataTemplate(arialLabelledBy, id) {
            return html `
      <div class="no-data" aria-labelledby="${arialLabelledBy}" id="${id}" role="tabpanel">No data available.</div>
    `;
        }
        renderAssertions(info) {
            if (!info) {
                return html ``;
            }
            const { assertions } = info;
            if (!Array.isArray(assertions) || !assertions.length) {
                return html `<p aria-labelledby="assertions-tab" id="assertions" role="tabpanel" class="no-data">
        No assertions defined.
      </p>`;
            }
            return html `
      <section aria-label="Assertions" aria-labelledby="assertions-tab" id="assertions" role="tabpanel">
        ${assertions.map((item, index) => html `
            ${this.renderAssertion(item)}
            ${index + 1 === assertions.length ? '' : html `<ui-divider type="inset"></ui-divider>`}
          `)}
      </section>
    `;
        }
        renderAssertion(item) {
            const { description, ok, error } = item;
            if (!ok) {
                return this.renderFailedAssertion(description, error);
            }
            return this.renderOkAssertion(description);
        }
        renderOkAssertion(description) {
            return html `
      <div class="assertion success">
        <ui-icon role="presentation" icon="check" class="assertion-icon primary-text"></ui-icon>
        <span class="label-large">${description}</span>
      </div>
    `;
        }
        renderFailedAssertion(description, error) {
            return html `
      <div class="assertion fail">
        <ui-icon role="presentation" icon="cancel" class="assertion-icon error-text"></ui-icon>
        <div class="fail-details">
          <span class="label-large">${description}</span>
          <span class="error-text body-large">${error.message}</span>
        </div>
      </div>
    `;
        }
        constructor() {
            super(...arguments);
            __runInitializers(this, _redirectsData_extraInitializers);
        }
    };
})();
/**
 * An element that renders the view for a core's `IRequestLog`.
 */
export default RequestLog;
//# sourceMappingURL=RequestLog.js.map