/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { html, TemplateResult } from 'lit'
import { ifDefined } from 'lit/directives/if-defined.js'
import { IAmfDomainElement, IAmfRequest, IAmfWebApi } from '@api-client/core/amf/definitions/Amf.js'
import { AmfNamespace } from '@api-client/core/amf/definitions/Namespace.js'
import { AmfMixin } from '@api-client/core/amf/AmfMixin.js'
import { AmfDemoPage } from './lib/AmfDemoPage.js'
import { reactive } from '../../src/decorators/index.js'
import { SelectionType } from '../../src/amf/types.js'
import type { ApiNavigationEvent } from '../../src/events/amf/NavigationEvents.js'
import '../../src/define/amf/api-schema-document.js'
import '../../src/md/checkbox/ui-checkbox.js'

class AmfHelper extends AmfMixin(Object) {}

class ComponentPage extends AmfDemoPage {
  @reactive() accessor selectedId: string | undefined

  @reactive() accessor selectedType: SelectionType | undefined

  @reactive() accessor mediaType: string | undefined

  @reactive() accessor mediaTypes: string[] | undefined

  @reactive() accessor shape: IAmfDomainElement | undefined

  @reactive() accessor noReadOnly: boolean | undefined

  @reactive() accessor forceExamples: boolean

  constructor() {
    super()

    this.forceExamples = true
    this.componentName = 'api-schema-document'
    this.typesOpened = true
    this.endpointsOpened = false
    this.mediaType = 'application/json'
    ;[
      ['APIC-649', 'Deprecated properties'],
      ['APIC-429', 'APIC 429'],
      ['read-only-properties', 'Read Only Properties API'],
      ['examples-api', 'Examples render demo'],
      ['Petstore-v2', 'OAS: Petstore'],
      ['apic-83', 'APIC-83'],
      ['SE-10469', 'SE-1046'],
      ['SE-11155', 'SE-11155'],
      ['APIC-282', 'APIC-282'],
      ['new-oas3-types', 'New OAS 3 types API'],
      ['APIC-483', 'APIC 483'],
      ['APIC-631', 'APIC-631: Arrays'],
      ['aap-1698', 'aap-1698'],
    ].forEach(([file, label]) => {
      this.apis.push({
        file: `models/${file}.json`,
        label,
      })
    })

    this.autoLoad()
  }

  override _navChanged(e: ApiNavigationEvent): void {
    const { domainId, domainType, passive } = e.detail
    if (passive) {
      return
    }
    this.selectedId = undefined
    this.selectedType = undefined
    this.shape = undefined
    this.mediaTypes = undefined
    this.mediaType = undefined

    if (domainType === 'schema') {
      this.setTypeData(domainId)
    } else if (domainType === 'operation') {
      this.setBodyData(domainId)
    }
  }

  setTypeData(id: string): void {
    this.selectedId = id
    this.selectedType = 'schema'
    this.readApiMediaTypes()
  }

  setBodyData(id: string): void {
    const helper = new AmfHelper()
    helper.amf = this.amf

    const webApi = helper._computeWebApi(helper.amf)
    const method = helper._computeMethodModel(webApi, id)
    const expects = helper._computeExpects(method)!
    const payload = (
      expects
        ? (expects![
            helper._getAmfKey(AmfNamespace.aml.vocabularies.apiContract.payload) as keyof IAmfRequest
          ] as IAmfDomainElement[][0] as IAmfDomainElement)
        : {}
    ) as IAmfDomainElement
    const mt = helper._getValue(payload, AmfNamespace.aml.vocabularies.core.mediaType) as string | undefined
    const key = helper._getAmfKey(AmfNamespace.aml.vocabularies.shapes.schema)
    let schema = payload && payload[key as keyof IAmfDomainElement]
    if (!schema) {
      return
    }
    schema = Array.isArray(schema) ? schema[0] : schema
    this.shape = schema as unknown as IAmfDomainElement
    this.mediaType = mt
  }

  readApiMediaTypes(): void {
    const helper = new AmfHelper()
    helper.amf = this.amf

    let webApi = helper._computeWebApi(helper.amf)
    if (webApi instanceof Array) {
      ;[webApi] = webApi
    }
    if (!webApi) {
      return
    }
    const key = helper._getAmfKey(AmfNamespace.aml.vocabularies.apiContract.accepts)
    const value = helper._ensureArray(webApi[key as keyof IAmfWebApi]) as string[]
    if (value) {
      this.mediaTypes = [...value]
      this.mediaType = value[0]
    }
  }

  mimeHandler(e: Event): void {
    const select = e.target as HTMLSelectElement
    this.mediaType = select.value
  }

  contentTemplate(): TemplateResult {
    return html`
      <a href="./">Back</a>
      ${this.demoTemplate()}
    `
  }

  demoTemplate(): TemplateResult {
    const { loaded } = this
    return html` ${!loaded ? html`<p>Load an API model first.</p>` : this._componentTemplate()} `
  }

  _componentTemplate(): TemplateResult {
    const { selectedId, forceExamples, shape, mediaType, noReadOnly } = this
    if (!selectedId && !shape) {
      return html`<p>Select API object in the navigation</p>`
    }
    return html`
      <section class="demo-section">
        <api-schema-document
          slot="content"
          .domainId="${shape && shape['@id']}"
          domainId="${ifDefined(selectedId)}"
          mimeType="${ifDefined(mediaType)}"
          ?forceExamples="${forceExamples}"
          ?noReadOnly="${noReadOnly}"
        ></api-schema-document>
      </section>

      <section class="demo-section">
        <label class="block" id="mainOptionsLabel">Options</label>
        <label class="label-large">
          <ui-checkbox
            @change="${this._toggleBooleanOption}"
            ?checked="${forceExamples}"
            name="forceExamples"
            aria-describedby="mainOptionsLabel"
          ></ui-checkbox>
          Force examples
        </label>

        <label class="label-large">
          <ui-checkbox
            @change="${this._toggleBooleanOption}"
            ?checked="${noReadOnly}"
            name="noReadOnly"
            aria-describedby="mainOptionsLabel"
            title="When set it does not render read only items. Read only property is a feature of OAS."
          ></ui-checkbox>
          No read only
        </label>
      </section>
    `
  }

  mediaTypesSelectorTemplate(): TemplateResult | string {
    const { mediaTypes } = this
    if (!Array.isArray(mediaTypes) || !mediaTypes.length) {
      return ''
    }
    return html`
      <select @change="${this.mimeHandler}" @blur="${this.mimeHandler}">
        <option value="">As in spec</option>
        ${mediaTypes.map(
          (mime) => html`<option ?selected="${mime === this.mediaType}" value="${mime}">${mime}</option>`
        )}
      </select>
    `
  }
}
const instance = new ComponentPage()
instance.render()
