import { html, type TemplateResult, nothing } from 'lit'
import { property, state } from 'lit/decorators.js'
import { ApiEditor } from './ApiEditor.js'
import { apiActionKindToIcon } from '../lib/ui_mapping.js'
import type { DeleteAction, ApiModel, DomainEntity, ExposedEntity } from '@api-client/core/browser.js'
import type { TabSelectionDetail } from '../../md/tabs/ui-tabs.js'
import { renderHelp } from '../../help/render.js'
import type { UiSelectChangeEvent } from '../../md/select/ui-select.js'

export default class ApiDeleteActionEditor extends ApiEditor {
  /**
   * Computed exposed entity being edited.
   */
  @state() accessor exposed: ExposedEntity | undefined
  /**
   * Computed domain entity that corresponds to the exposed entity being edited.
   */
  @state() accessor entity: DomainEntity | undefined
  /**
   * Computed delete action definition being edited.
   */
  @state() accessor action: DeleteAction | undefined
  /**
   * When true, shows a close button in the editor header.
   * @attribute
   */
  @property({ type: Boolean }) accessor showCloseButton = false
  /**
   * The currently active tab index.
   */
  @state() accessor activeTab = 0

  protected override setupModel(model?: ApiModel, domainKey?: string): void | Promise<void> {
    this.exposed = undefined
    this.entity = undefined
    this.action = undefined
    if (!model || !domainKey) {
      return
    }
    const exposed = model.exposes.find((exposed) => exposed.key === domainKey)
    this.exposed = exposed
    if (!exposed) {
      return
    }
    const domain = model.domain
    if (!domain) {
      return
    }
    const entity = domain.findEntity(exposed.entity.key, exposed.entity.domain)
    if (!entity) {
      return
    }
    this.entity = entity
    const action = exposed.actions.find((action) => action.kind === 'delete')
    this.action = action
  }

  protected handleCloseButtonClick(): void {
    this.dispatchEvent(new Event('close'))
  }

  /**
   * Handles tab change events.
   */
  protected handleTabChange(e: CustomEvent<TabSelectionDetail>): void {
    this.activeTab = e.detail.index
  }

  protected handleConfigurationChange(): void {
    this.notifyChange()
  }

  protected handleDeleteStrategyChange(e: CustomEvent<UiSelectChangeEvent>): void {
    const { value } = e.detail
    if (!value) {
      return
    }
    this.updateDeleteStrategy(value)
  }

  updateDeleteStrategy(strategy: string): void {
    if (!['soft', 'hard'].includes(strategy)) {
      throw new Error(`Invalid delete strategy: ${strategy}.`)
    }
    if (!this.action) {
      throw new Error('No action is set.')
    }
    this.action.strategy = strategy as 'soft' | 'hard'
    this.notifyChange()
    this.requestUpdate()
  }

  protected handleRetentionPeriodChange(e: Event): void {
    const input = e.target as HTMLInputElement
    const value = input.valueAsNumber
    if (isNaN(value)) {
      return
    }
    this.updateRetentionPeriod(value)
  }

  updateRetentionPeriod(retentionPeriod: number): void {
    if (retentionPeriod < 1) {
      throw new Error('Retention period must be at least 1 day.')
    }
    if (!this.action) {
      throw new Error('No action is set.')
    }
    this.action.retentionPeriod = retentionPeriod
    this.notifyChange()
    this.requestUpdate()
  }

  protected override render(): TemplateResult | typeof nothing {
    if (!this.exposed || !this.entity || !this.action) {
      return nothing
    }
    return html`<div class="container">${this.renderHeader()} ${this.renderTabs()} ${this.renderTabContent()}</div>`
  }

  /**
   * Renders a template of the editor header.
   */
  protected renderHeader(): TemplateResult {
    const { entity } = this
    let label = 'Delete action'
    if (entity) {
      label = entity.info.getLabel() + ': Delete action'
    }
    return html`<div class="intro">
      <div class="header">
        <ui-icon>${apiActionKindToIcon('delete')}</ui-icon>
        <span class="headline-medium">${label}</span>
        ${this.renderCloseButton()}
      </div>
      <div class="body-medium description">Delete action allows removing a resource from the collection.</div>
    </div>`
  }

  /**
   * Renders the tabs navigation.
   */
  protected renderTabs(): TemplateResult {
    return html`<ui-tabs
      class="tabs"
      .activeTabIndex="${this.activeTab}"
      @change="${this.handleTabChange}"
      priority="secondary"
    >
      <ui-tab>Configuration</ui-tab>
      <ui-tab>Access</ui-tab>
      <ui-tab>Limits</ui-tab>
    </ui-tabs>`
  }

  /**
   * Renders the content for the currently active tab.
   */
  protected renderTabContent(): TemplateResult | typeof nothing {
    if (!this.action) {
      return nothing
    }
    switch (this.activeTab) {
      case 0:
        return this.renderConfigurationTab()
      case 1:
        return this.renderAccessTab()
      case 2:
        return this.renderLimitsTab()
      default:
        return nothing
    }
  }

  /**
   * Renders the Configuration tab content.
   */
  protected renderConfigurationTab(): TemplateResult | typeof nothing {
    if (!this.action) {
      return nothing
    }
    return html`<div class="configuration-tab">${this.renderUpdateConfiguration(this.action)}</div>`
  }

  /**
   * Renders the Access tab content.
   */
  protected renderAccessTab(): TemplateResult {
    return html`<div class="config-section">
      <api-modeling-access-configuration
        .model="${this.model}"
        domainKey="${this.exposed?.key || ''}"
        operation="delete"
        target="action"
        class="access-configuration"
        @change="${this.handleConfigurationChange}"
      ></api-modeling-access-configuration>
    </div>`
  }

  /**
   * Renders the Limits tab content.
   */
  protected renderLimitsTab(): TemplateResult {
    return html`<div class="config-section">
      <api-modeling-rate-limiting
        .model="${this.model}"
        domainKey="${this.exposed?.key || ''}"
        operation="delete"
        target="action"
        class="rate-limiting-configuration"
        @change="${this.handleConfigurationChange}"
      ></api-modeling-rate-limiting>
    </div>`
  }

  /**
   * Renders the close button if the `showCloseButton` flag is set.
   */
  protected renderCloseButton(): TemplateResult | typeof nothing {
    if (!this.showCloseButton) {
      return nothing
    }
    return html`<ui-icon-button
      color="outlined"
      class="close-button"
      aria-label="Close editor"
      @click="${this.handleCloseButtonClick}"
    >
      <ui-icon icon="close"></ui-icon>
    </ui-icon-button>`
  }

  protected renderUpdateConfiguration(action: DeleteAction): TemplateResult {
    return html`<div class="delete-configuration config-section">
      <div class="config-intro">
        <div class="section-header">
          <span class="title-large">Delete mode</span>
          ${renderHelp('modeling', 'api:delete-mode')}
        </div>
        <div class="section-description body-medium">Configure the delete mode of the resource.</div>
      </div>

      <div class="row input-row">
        <ui-select
          class="input"
          label="Deletion mode"
          .value="${action.strategy}"
          @change="${this.handleDeleteStrategyChange}"
        >
          <ui-option value="soft">Soft delete</ui-option>
          <ui-option value="hard">Hard delete</ui-option>
        </ui-select>
      </div>

      <div class="row input-row">
        <ui-outlined-text-field
          class="input"
          label="Retention period (days)"
          type="number"
          .value="${String(action.retentionPeriod || '30')}"
          min="1"
          @change="${this.handleRetentionPeriodChange}"
        ></ui-outlined-text-field>
        ${renderHelp('modeling', 'api:delete-action:retention-period')}
      </div>
    </div>`
  }
}
