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 { UpdateAction, ApiModel, DomainEntity, ExposedEntity } from '@api-client/core/browser.js'
import type { TabSelectionDetail } from '../../md/tabs/ui-tabs.js'
import type { UiCheckboxElement } from '../../md/checkbox/ui-checkbox.js'
import { renderHelp } from '../../help/render.js'

export default class ApiUpdateActionEditor 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 create action definition being edited.
   */
  @state() accessor action: UpdateAction | 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 === 'update')
    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 handleMethodChange(e: Event): void {
    const checkbox = e.target as UiCheckboxElement
    const { value = '', checked = false } = checkbox
    if (!['PUT', 'PATCH'].includes(value)) {
      return
    }
    this.toggleMethod(value as 'PUT' | 'PATCH', checked)
  }

  toggleMethod(method: 'PUT' | 'PATCH', enabled: boolean): void {
    if (!this.action) {
      throw new Error('No action is set.')
    }
    const methods = new Set(this.action.allowedMethods)
    if (enabled) {
      methods.add(method)
    } else {
      methods.delete(method)
    }
    this.action.allowedMethods = Array.from(methods)
    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 = 'Update action'
    if (entity) {
      label = entity.info.getLabel() + ': Update action'
    }
    return html`<div class="intro">
      <div class="header">
        <ui-icon>${apiActionKindToIcon('update')}</ui-icon>
        <span class="headline-medium">${label}</span>
        ${this.renderCloseButton()}
      </div>
      <div class="body-medium description">Update action allows updating a resource.</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="update"
        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="update"
        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: UpdateAction): TemplateResult {
    const hasPut = action.allowedMethods.includes('PUT')
    const hasPatch = action.allowedMethods.includes('PATCH')
    return html`<div class="update-configuration config-section">
      <div class="config-intro">
        <div class="section-header">
          <span class="title-large">Update method</span>
          ${renderHelp('modeling', 'api:update-method')}
        </div>
        <div class="section-description body-medium">Choose the method for updating the resource.</div>
      </div>

      <div class="row">
        <div class="input checkbox metadata">
          <ui-checkbox
            id="method-put"
            name="method"
            value="PUT"
            .checked="${hasPut}"
            @change="${this.handleMethodChange}"
          ></ui-checkbox>
          <div class="label">
            <label for="method-put" class="body-medium">Replace (PUT)</label>
            <span class="body-small meta">Replaces the entire resource with the provided data.</span>
          </div>
        </div>
        ${renderHelp('taxonomy', 'api:update-method:put')}
      </div>

      <div class="row">
        <div class="input checkbox metadata">
          <ui-checkbox
            id="method-patch"
            name="method"
            value="PATCH"
            .checked="${hasPatch}"
            @change="${this.handleMethodChange}"
          ></ui-checkbox>
          <div class="label">
            <label for="method-patch" class="body-medium">Partial (PATCH)</label>
            <span class="body-small meta"
              >Applies a partial update to the resource, allowing for specific fields to be modified.</span
            >
          </div>
        </div>
        ${renderHelp('taxonomy', 'api:update-method:patch')}
      </div>
    </div>`
  }
}
