import { DEFAULT_SKU_CONFIG, type SKUConfig } from '@api-client/core/modeling/definitions/SKU.js'
import { TaxonomyDialog } from './TaxonomyDialog.js'
import type { DomainProperty } from '@api-client/core/modeling/DomainProperty.js'
import { SemanticType } from '@api-client/core/modeling/Semantics.js'
import { bound } from '../../decorators/bound.js'
import { html, nothing, TemplateResult } from 'lit'
import { renderHelp } from '../../help/render.js'
import type { UiOutlinedTextFieldElement } from '../../md/text-field/ui-outlined-text-field.js'
import { repeat } from 'lit/directives/repeat.js'

import '../../md/divider/ui-divider.js'

export class SkuTaxonomy extends TaxonomyDialog<SKUConfig> {
  static override title = `Configure SKU Taxonomy`

  /**
   * The list of properties available for source list.
   * It is a computed list for the parent entity and all its parents.
   */
  properties: DomainProperty[] = []

  constructor(public domainElement: DomainProperty) {
    let config: SKUConfig
    const semantic = domainElement.semantics.find((s) => s.id === SemanticType.SKU)
    if (semantic && semantic.config) {
      config = structuredClone(semantic.config) as SKUConfig
    } else {
      config = {}
    }
    super(config)
    const entity = domainElement.getParentInstance()
    if (entity) {
      this.properties = this.listComputedProperties(entity, {
        exclude: [this.domainElement.key],
        types: ['string', 'number'],
      })
    }
  }

  protected override formCallback(event: Event): Promise<void> {
    const semantic = this.domainElement.semantics.find((s) => s.id === SemanticType.SKU)
    if (semantic) {
      semantic.config = this.config
    } else {
      this.domainElement.semantics.push({
        id: SemanticType.SKU,
        config: this.config,
      })
    }
    this.domainElement.domain.notifyChange()
    return super.formCallback(event)
  }

  @bound
  handleCustomPatternChange(event: Event): void {
    const input = event.target as UiOutlinedTextFieldElement
    const value = input.value.trim()
    if (!value) {
      delete this.config.customPattern
    } else if (this.isValidRegex(value)) {
      this.config.customPattern = value
    } else {
      input.invalidText = 'Invalid regular expression pattern'
      input.invalid = true
      return
    }
    input.invalid = false
    this.requestUpdate()
  }

  isValidRegex(pattern: string): boolean {
    try {
      new RegExp(pattern)
      return true
    } catch {
      return false
    }
  }

  @bound
  handleReservedValuesChange(event: Event): void {
    const input = event.target as HTMLInputElement
    const value = input.value.trim()
    if (value) {
      const reservedValues = this.config?.reservedValues ?? DEFAULT_SKU_CONFIG.reservedValues ?? []
      if (!reservedValues.includes(value)) {
        reservedValues.push(value)
        this.config = { ...this.config, reservedValues }
        this.requestUpdate()
      }
      input.value = ''
    }
  }

  @bound
  handleRemoveReservedValue(event: Event): void {
    const chip = event.currentTarget as HTMLElement
    const index = parseInt(chip.dataset.index || '-1', 10)
    if (index >= 0 && this.config?.reservedValues) {
      this.config.reservedValues.splice(index, 1)
      this.requestUpdate()
    }
  }

  @bound
  render(): TemplateResult {
    return html`
      <div class="input-group">
        ${this.renderValidationModeSelect()} ${this.renderCustomPatternInput()} ${this.renderCaseModeSelect()}
        ${this.renderPrefixInput()} ${this.renderReservedValuesInput()}
      </div>
      <div class="checkbox-group">
        ${this.renderEnforceUniqueness()} ${this.renderValidateReservedWords()} ${this.renderAutoGenerate()}
      </div>
      <div class="input-group">${this.renderAutoGenerateSourceSelect()}</div>
    `
  }

  protected renderValidationModeSelect(): TemplateResult {
    const value = this.config?.validationMode ?? DEFAULT_SKU_CONFIG.validationMode
    return html`
      <div class="row">
        <ui-select
          label="Validation mode"
          class="input"
          name="validationMode"
          .value="${value as string}"
          @change="${this.handleSelectChange}"
        >
          <ui-option value="strict">Strict</ui-option>
          <ui-option value="lenient">Lenient</ui-option>
          <ui-option value="custom">Custom</ui-option>
        </ui-select>
        ${renderHelp('taxonomy', 'sku:validationMode')}
      </div>
    `
  }

  protected renderCustomPatternInput(): TemplateResult | typeof nothing {
    const mode = this.config?.validationMode ?? DEFAULT_SKU_CONFIG.validationMode
    if (mode !== 'custom') {
      return nothing
    }
    const value = this.config?.customPattern ?? DEFAULT_SKU_CONFIG.customPattern
    return html`
      <div class="row input-row">
        <ui-outlined-text-field
          label="Custom Pattern"
          class="input"
          name="customPattern"
          .value="${value as string}"
          @change="${this.handleCustomPatternChange}"
          required
        ></ui-outlined-text-field>
        ${renderHelp('taxonomy', 'sku:customPattern')}
      </div>
    `
  }

  protected renderCaseModeSelect(): TemplateResult {
    const value = this.config?.caseMode ?? DEFAULT_SKU_CONFIG.caseMode
    return html`
      <div class="row input-row">
        <ui-select
          label="Case Mode"
          class="input"
          name="caseMode"
          .value="${value as string}"
          @change="${this.handleSelectChange}"
        >
          <ui-option value="uppercase">Uppercase</ui-option>
          <ui-option value="lowercase">Lowercase</ui-option>
          <ui-option value="preserve">Preserve Case</ui-option>
        </ui-select>
        ${renderHelp('taxonomy', 'sku:caseMode')}
      </div>
    `
  }

  protected renderPrefixInput(): TemplateResult {
    const value = this.config?.prefix ?? DEFAULT_SKU_CONFIG.prefix
    return html`
      <div class="row input-row">
        <ui-outlined-text-field
          label="Prefix"
          class="input"
          name="prefix"
          .value="${value as string}"
          @change="${this.handleTextChange}"
        ></ui-outlined-text-field>
        ${renderHelp('taxonomy', 'sku:prefix')}
      </div>
    `
  }

  protected renderReservedValuesInput(): TemplateResult {
    const value = this.config?.reservedValues ?? DEFAULT_SKU_CONFIG.reservedValues
    const chips = (value || []).map(
      (val, index) =>
        html`<ui-chip type="input" removable data-index="${index}" @remove="${this.handleRemoveReservedValue}"
          >${val}</ui-chip
        >`
    )
    return html`
      <div class="row input-row">
        <div class="input chips-input">
          <ui-outlined-text-field
            class="input"
            name="reservedValues"
            label="Reserved Values"
            @change="${this.handleReservedValuesChange}"
            supportingText="Add a reserved value and press Enter to add it to the list."
          ></ui-outlined-text-field>
          <ui-chip-set>${chips}</ui-chip-set>
        </div>
        ${renderHelp('taxonomy', 'sku:reservedValues')}
      </div>
    `
  }

  protected renderEnforceUniqueness(): TemplateResult {
    const value = this.config?.enforceUniqueness ?? DEFAULT_SKU_CONFIG.enforceUniqueness
    return html`
      <div class="row">
        <div class="input checkbox metadata">
          <ui-checkbox
            id="enforce-uniqueness"
            name="enforceUniqueness"
            .checked="${value}"
            @change="${this.handleBooleanChange}"
          ></ui-checkbox>
          <div class="label">
            <label for="enforce-uniqueness" class="body-medium">Enforce Uniqueness</label>
            <span class="body-small meta">Whether to enforce global uniqueness across all entities.</span>
          </div>
        </div>
        ${renderHelp('taxonomy', 'sku:enforceUniqueness')}
      </div>
    `
  }

  protected renderValidateReservedWords(): TemplateResult {
    const value = this.config?.validateReservedWords ?? DEFAULT_SKU_CONFIG.validateReservedWords
    return html`
      <div class="row">
        <div class="input checkbox metadata">
          <ui-checkbox
            id="validate-reserved-words"
            name="validateReservedWords"
            .checked="${value}"
            @change="${this.handleBooleanChange}"
          ></ui-checkbox>
          <div class="label">
            <label for="validate-reserved-words" class="body-medium">Validate Reserved Words</label>
            <span class="body-small meta">Whether to validate against reserved words.</span>
          </div>
        </div>
        ${renderHelp('taxonomy', 'sku:validateReservedWords')}
      </div>
    `
  }

  protected renderAutoGenerate(): TemplateResult {
    const value = this.config?.autoGenerate ?? DEFAULT_SKU_CONFIG.autoGenerate
    return html`
      <div class="row">
        <div class="input checkbox metadata">
          <ui-checkbox
            id="auto-generate"
            name="autoGenerate"
            .checked="${value}"
            @change="${this.handleBooleanChange}"
          ></ui-checkbox>
          <div class="label">
            <label for="auto-generate" class="body-medium">Auto Generate</label>
            <span class="body-small meta">Whether to auto-generate SKUs for new entities.</span>
          </div>
        </div>
        ${renderHelp('taxonomy', 'sku:autoGenerate')}
      </div>
    `
  }

  protected renderAutoGenerateSourceSelect(): TemplateResult | typeof nothing {
    const autoGenerate = this.config?.autoGenerate ?? DEFAULT_SKU_CONFIG.autoGenerate
    if (!autoGenerate) {
      return nothing
    }
    const value = this.config?.autoGenerateSource ?? DEFAULT_SKU_CONFIG.autoGenerateSource
    return html`
      <div class="row input-row">
        <ui-select
          label="Auto Generate Source"
          class="input"
          name="autoGenerateSource"
          .value="${value as string}"
          @change="${this.handleSelectChange}"
        >
          <ui-option value="">
            <div>Random</div>
            <div slot="supporting-text">Use a randomly generated value.</div>
          </ui-option>
          <ui-divider></ui-divider>
          ${repeat(
            this.properties,
            (prop) => prop.key,
            (prop) => {
              return html`
                <ui-option value="${prop.key}">
                  <div>${prop.info.getLabel()}</div>
                  ${prop.info.description ? html`<div slot="supporting-text">${prop.info.description}</div>` : nothing}
                </ui-option>
              `
            }
          )}
        </ui-select>
        ${renderHelp('taxonomy', 'sku:autoGenerateSource')}
      </div>
    `
  }
}
