import { html, LitElement, nothing, type PropertyValues, type TemplateResult } from 'lit'
import { property, state } from 'lit/decorators.js'
import { DomainAssociationKind, DomainEntityKind, DomainPropertyKind } from '@api-client/core/models/kinds.js'
import type { DomainValidation } from '@api-client/core/modeling/validation/rules.js'
import type { SchemaSelectionInfo } from '../types.js'
import type { DataDomain } from '@api-client/core/browser.js'

/**
 * An element that specializes in displaying a domain validation report.
 * It is used in the context of the domain validation process.
 *
 * The report is generated elsewhere and passed to this element for display.
 *
 * @fires openissue {CustomEvent<SchemaSelectionInfo>} Fired when the user clicks on the "Open" button
 *   of a validation issue.
 *   The detail contains `SchemaSelectionInfo` with the entity/property/association to navigate to.
 * @fires autofix - Fired when the user clicks on the "Auto fix" button.
 */
export default class DomainValidationReport extends LitElement {
  /**
   * The generated report of domain validation.
   */
  @property({ type: Array }) accessor report: DomainValidation[] = []

  /**
   * The domain that was validated.
   * This is used to provide context for the validation report.
   */
  @property({ type: Object }) accessor domain: DataDomain | undefined
  /**
   * When set to true, the UI will include an "Auto fix" button
   * that allows the user to attempt to automatically fix issues in the report.
   * The host must handle the `autofix` event to perform the actual fixing.
   * @attribute
   */
  @property({ type: Boolean }) accessor withAutoFix = false
  /**
   * The number of issues with the severity of "info".
   */
  @state() accessor infoCount = 0
  /**
   * The number of issues with the severity of "warning".
   */
  @state() accessor warningCount = 0
  /**
   * The number of issues with the severity of "error".
   */
  @state() accessor errorCount = 0
  /**
   * Controls which severity levels are currently shown.
   * Determines which validation messages are filtered and displayed.
   */
  @state() accessor visibleSeverities = new Set<'error' | 'warning' | 'info'>()
  /**
   * Cached filtered report based on current severity filters.
   * This improves performance by avoiding re-filtering on every render.
   */
  @state() accessor filteredReport: DomainValidation[] = []

  protected override willUpdate(cp: PropertyValues<this>): void {
    super.willUpdate(cp)
    if (cp.has('report')) {
      this.computeIssueCounters()
      this.setDefaultFilters()
      this.updateFilteredReport()
    }
    if (cp.has('visibleSeverities')) {
      this.updateFilteredReport()
    }
  }

  /**
   * Computes the number of issues in the report based on their severity.
   * This method is called whenever the `report` is updated.
   */
  protected computeIssueCounters(): void {
    this.infoCount = this.report.filter((validation) => validation.severity === 'info').length
    this.warningCount = this.report.filter((validation) => validation.severity === 'warning').length
    this.errorCount = this.report.filter((validation) => validation.severity === 'error').length
  }

  /**
   * Sets the default filters based on available issues.
   * By default shows errors. If no errors, shows warnings. Never shows notices by default.
   */
  protected setDefaultFilters(): void {
    if (this.errorCount > 0) {
      this.visibleSeverities = new Set(['error'])
    } else if (this.warningCount > 0) {
      this.visibleSeverities = new Set(['warning'])
    } else {
      this.visibleSeverities = new Set()
    }
  }

  /**
   * Updates the filtered report based on the current severity filters.
   * This method is called whenever the visibility filters change.
   */
  protected updateFilteredReport(): void {
    this.filteredReport = this.report.filter((validation) =>
      this.visibleSeverities.has(validation.severity as 'error' | 'warning' | 'info')
    )
  }

  /**
   * Handles the filter button click events.
   * Toggles the visibility of validation messages by severity.
   */
  protected handleFilterClick(e: Event): void {
    const target = e.target as HTMLElement
    const severity = target.dataset.severity as 'error' | 'warning' | 'info'
    if (!severity) {
      return
    }

    const newVisibleSeverities = new Set(this.visibleSeverities)
    if (newVisibleSeverities.has(severity)) {
      newVisibleSeverities.delete(severity)
    } else {
      newVisibleSeverities.add(severity)
    }
    this.visibleSeverities = newVisibleSeverities
  }

  /**
   * A handler for the "Open" button click event.
   * It prepares the Intent data to be used to run the activity
   * that will open the corresponding issue.
   */
  protected handleOpenIssue(e: Event): void {
    const target = e.target as HTMLElement
    const index = target.dataset.index
    if (!index) {
      return
    }
    const validation = this.filteredReport[Number(index)]
    if (!validation) {
      return
    }
    const { key, kind, parent } = validation
    const data: SchemaSelectionInfo = {}
    if (kind === DomainEntityKind) {
      data.selection = {
        key,
        kind,
        domain: this.domain?.key || '',
      }
    } else if (kind === DomainPropertyKind && parent) {
      data.selection = {
        key: parent,
        kind: DomainEntityKind,
        domain: this.domain?.key || '',
      }
      data.field = {
        key,
        kind,
        domain: this.domain?.key || '',
      }
    } else if (kind === DomainAssociationKind && parent) {
      data.selection = {
        key: parent,
        kind: DomainEntityKind,
        domain: this.domain?.key || '',
      }
      data.field = {
        key,
        kind,
        domain: this.domain?.key || '',
      }
    } else {
      return
    }
    const ev = new CustomEvent('openissue', {
      detail: data,
      bubbles: true,
      composed: true,
    })
    this.dispatchEvent(ev)
    // Events.Intent.startActivity(
    //   {
    //     action: QUICK_API_SCHEMA,
    //     data,
    //   },
    //   this
    // )
  }

  handleAutoFix(): void {
    this.dispatchEvent(new Event('autofix'))
  }

  override render(): TemplateResult | typeof nothing {
    if (this.report.length === 0) {
      return nothing
    }
    return html`
      <div class="validation-report-content">
        ${this.#renderFilters()}${this.#renderStatus()}
        <ul class="report">
          ${this.filteredReport.map((validation, i) => this.#renderValidation(validation, i))}
        </ul>
      </div>
    `
  }

  #renderStatus(): TemplateResult {
    const filteredCount = this.filteredReport.length
    const totalCount = this.report.length

    return html` <div class="status">Showing ${filteredCount} of ${totalCount}</div> `
  }

  #renderFilters(): TemplateResult {
    const isErrorVisible = this.visibleSeverities.has('error')
    const isWarningVisible = this.visibleSeverities.has('warning')
    const isInfoVisible = this.visibleSeverities.has('info')

    return html`
      <div class="filters" @click="${this.handleFilterClick}">
        <ui-button-group type="connected" multiple>
          <ui-button
            color="tonal"
            size="xs"
            toggle
            data-severity="error"
            ?selected="${isErrorVisible}"
            ?disabled="${this.errorCount === 0}"
          >
            ${isErrorVisible ? html`<ui-icon slot="icon">check</ui-icon>` : nothing}Errors (${this.errorCount})
          </ui-button>
          <ui-button
            color="tonal"
            size="xs"
            toggle
            data-severity="warning"
            ?selected="${isWarningVisible}"
            ?disabled="${this.warningCount === 0}"
          >
            ${isWarningVisible ? html`<ui-icon slot="icon">check</ui-icon>` : nothing}Warnings (${this.warningCount})
          </ui-button>
          <ui-button
            color="tonal"
            size="xs"
            toggle
            data-severity="info"
            ?selected="${isInfoVisible}"
            ?disabled="${this.infoCount === 0}"
          >
            ${isInfoVisible ? html`<ui-icon slot="icon">check</ui-icon>` : nothing}Notices (${this.infoCount})
          </ui-button>
        </ui-button-group>
        ${this.withAutoFix ? this.#renderAutoFixButton() : nothing}
      </div>
    `
  }

  #renderAutoFixButton(): TemplateResult {
    return html`
      <ui-button color="outlined" @click="${this.handleAutoFix}" title="Fix all auto fixable issues">
        <ui-icon slot="icon">autorenew</ui-icon> Auto fix
      </ui-button>
    `
  }

  #renderValidation(validation: DomainValidation, index: number): TemplateResult {
    const { message, severity, help } = validation
    let icon = ''
    switch (severity) {
      case 'warning':
        icon = 'warning'
        break
      case 'error':
        icon = 'error'
        break
      default:
        icon = 'info'
        break
    }
    return html`
      <li class="${severity}">
        <ui-icon class="report-icon">${icon}</ui-icon>
        <div class="report-details">
          <span class="report-message">${message}</span>
          ${help ? html`<span class="report-help">${help}</span>` : ''}
        </div>
        <ui-button color="text" data-index="${index}" @click="${this.handleOpenIssue}">Open</ui-button>
      </li>
    `
  }
}
