import { html, TemplateResult, PropertyValues } from 'lit'
import { type IRequestTime, RequestTime } from '@api-client/core/models/RequestTime.js'
import { property, state } from 'lit/decorators.js'
import { ITimingViewData, ITimingProgressInfo, computeTimingsViewData } from '../../lib/http/Har.js'
import ApiElement from '../ApiElement.js'
import '../../md/date/ui-date-time.js'
import '../../md/progress/ui-progress.js'

export default class LogTimings extends ApiElement {
  /**
   * The ordered list of timings for each redirect.
   * The last timing is the final request.
   */
  @property({ type: Array }) accessor timings: (RequestTime | IRequestTime)[] | undefined

  /**
   * When set it renders mobile friendly view
   * @attribute
   */
  @property({ type: Boolean, reflect: true }) accessor narrow = false

  @state() protected accessor withRedirects = false

  @state() protected accessor viewData: ITimingViewData[] = []

  @state() protected accessor totalTime = 0

  protected override willUpdate(cp: PropertyValues<this>): void {
    super.updated(cp)
    if (cp.has('timings')) {
      this.processTimings()
    }
  }

  protected processTimings(): void {
    const { timings } = this
    if (!timings) {
      this.viewData = []
      this.withRedirects = false
      this.totalTime = 0
      return
    }
    this.withRedirects = timings.length > 1
    this.viewData = computeTimingsViewData(timings)
    this.totalTime = this.viewData.reduce((prev, current) => prev + current.duration, 0)
  }

  protected override render(): TemplateResult {
    const { viewData, withRedirects } = this
    if (!Array.isArray(viewData) || !viewData.length) {
      return this.renderNoData()
    }
    if (withRedirects) {
      return this.renderRedirectsTable()
    }
    return this.renderTiming(viewData[0])
  }

  protected renderNoData(): TemplateResult {
    return html` <div class="no-data">No data available.</div> `
  }

  protected renderRedirectsTable(): TemplateResult {
    const { totalTime, viewData } = this
    const items = [...viewData]
    const last = items.pop() as ITimingViewData
    return html`
      <section class="redirects">
        <h3 class="sub-title">Redirects</h3>
        ${items.map((item, index) => this.renderRedirectItem(item, index))}
        <h3 class="sub-title">Final request</h3>
        <div class="timings-row">
          <div class="redirect-value">${this.renderTiming(last)}</div>
        </div>
        <div class="status-row">
          <div class="flex"></div>
          <span class="timing-value total text">Total: ${totalTime} ms</span>
        </div>
      </section>
    `
  }

  protected renderRedirectItem(item: ITimingViewData, index: number): TemplateResult {
    return html`
      <div class="timings-row">
        <div class="status-label text">#<span>${index + 1}</span></div>
        <div class="redirect-value">${this.renderTiming(item)}</div>
      </div>
    `
  }

  /**
   * @returns The template for a single timing item.
   */
  protected renderTiming(info: ITimingViewData): TemplateResult {
    const { data, duration } = info
    const { blocked, connect, dns, receive, send, wait, ssl } = data
    return html`
      ${this.renderTimingRow(duration, blocked)} ${this.renderTimingRow(duration, dns)}
      ${this.renderTimingRow(duration, connect)} ${this.renderTimingRow(duration, ssl)}
      ${this.renderTimingRow(duration, send)} ${this.renderTimingRow(duration, wait)}
      ${this.renderTimingRow(duration, receive)}
      <div class="row is-total">
        <span class="timing-value total">${info.duration} ms</span>
      </div>
    `
  }

  /**
   * Renders a single timing row.
   * @param duration Max value of the progress
   * @param info The computed timing values.
   */
  protected renderTimingRow(duration: number, info?: ITimingProgressInfo): TemplateResult | string {
    if (!info || typeof info.label === 'undefined') {
      return ''
    }
    return html`
      <div class="row" data-type="${info.type}-time">
        <div class="timing-label label">${info.title}</div>
        <ui-progress
          aria-label="${info.ariaLabel}"
          .value="${info.previous}"
          .secondaryProgress="${info.value}"
          .max="${duration}"
          step="0.0001"
        ></ui-progress>
        <span class="timing-value">${info.label} ms</span>
      </div>
    `
  }

  /**
   * Renders the start time row
   * @param time The timestamp of the request
   */
  protected renderStartTime(time: number): TemplateResult | string {
    if (typeof time !== 'number') {
      return ''
    }
    return html` <div class="row" data-type="start-time">
      <span class="label">Start date:</span>
      <ui-date-time
        year="numeric"
        month="numeric"
        day="numeric"
        hour="numeric"
        minute="numeric"
        second="numeric"
        class="date-value"
        .date="${time}"
      ></ui-date-time>
    </div>`
  }
}
