import { html, TemplateResult } from 'lit'
import type { IAmfRequest, IAmfPayload, IAmfOperation, IAmfResponse } from '@api-client/core/amf/definitions/Amf.js'
import { AmfMixin } from '@api-client/core/amf/AmfMixin.js'
import { AmfNamespace } from '@api-client/core/amf/definitions/Namespace.js'
import { AmfDemoPage } from './lib/AmfDemoPage.js'
import { reactive } from '../../src/decorators/index.js'
import type { ApiNavigationEvent } from '../../src/events/amf/NavigationEvents.js'
import '../../src/define/amf/api-payload-document.js'

class AmfHelper extends AmfMixin(Object) {}

interface ResponsePayload {
  code: string
  payloads: IAmfPayload[]
}

class ComponentPage extends AmfDemoPage {
  @reactive() accessor request: IAmfPayload[] | undefined

  @reactive() accessor response: ResponsePayload[] | undefined

  constructor() {
    super()
    this.componentName = 'api-payload-document'

    this.apis = [
      ...this.apis,
      {
        file: 'models/SE-11508.json',
        label: 'SE-11508',
      },
      {
        file: 'models/SE-12291.json',
        label: 'OAS "and" type',
      },
      {
        file: 'models/APIC-463.json',
        label: 'APIC-463',
      },
      {
        file: 'models/anyOf.json',
        label: 'AnyOf',
      },
      {
        file: 'models/stevetest.json',
        label: 'stevetest',
      },
    ]
    this.autoLoad()
  }

  override _navChanged(e: ApiNavigationEvent): void {
    const { domainId, domainType, passive } = e.detail
    if (passive) {
      return
    }
    this.request = []
    this.response = []
    if (domainType === 'operation') {
      this.setPayloads(domainId)
    }
  }

  setPayloads(operationId: string): void {
    const helper = new AmfHelper()
    helper.amf = this.amf

    const webApi = helper._computeApi(helper.amf)
    const operation = helper._computeMethodModel(webApi, operationId)
    if (!operation) {
      return
    }
    const expects = helper._computeExpects(operation)
    if (expects) {
      let payloads = expects[
        helper._getAmfKey(AmfNamespace.aml.vocabularies.apiContract.payload) as keyof IAmfRequest
      ] as IAmfPayload[]
      if (payloads) {
        if (!Array.isArray(payloads)) {
          payloads = [payloads]
        }
        this.request = payloads
      }
    }

    const returns = operation[
      helper._getAmfKey(AmfNamespace.aml.vocabularies.apiContract.returns) as keyof IAmfOperation
    ] as IAmfResponse[]
    if (Array.isArray(returns)) {
      const result: ResponsePayload[] = []
      returns.forEach((response) => {
        const code = helper._getValue(response, AmfNamespace.aml.vocabularies.apiContract.statusCode) as string
        let payloads = response[
          helper._getAmfKey(AmfNamespace.aml.vocabularies.apiContract.payload) as keyof IAmfResponse
        ] as IAmfPayload[]
        if (payloads) {
          if (!Array.isArray(payloads)) {
            payloads = [payloads]
          }
          const item: ResponsePayload = {
            code,
            payloads,
          }
          result.push(item)
        }
      })
      this.response = result
    }
  }

  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.loadedTemplate()} `
  }

  loadedTemplate(): TemplateResult {
    const { request, response } = this
    const hasRequests = Array.isArray(request) && !!request.length
    const hasResponses = Array.isArray(response) && !!response.length
    if (!hasRequests && !hasResponses) {
      return html`<p>Select API operation in the navigation</p>`
    }
    return html` ${this.requestsTemplate()} ${this.responsesTemplate()} `
  }

  requestsTemplate(): TemplateResult | string {
    const { request } = this
    if (!Array.isArray(request) || !request.length) {
      return ''
    }
    return html`
      <div class="payload-section">
        <h3>Request payload</h3>
        ${request.map((p) => this.payloadTemplate(p))}
      </div>
    `
  }

  responsesTemplate(): TemplateResult | string {
    const { response } = this
    if (!Array.isArray(response) || !response.length) {
      return ''
    }
    return html`
      <div class="payload-section">
        <h3>Response payload</h3>
        ${response.map((item) => this.responseItemTemplate(item))}
      </div>
    `
  }

  responseItemTemplate(item: ResponsePayload): TemplateResult {
    const { code, payloads } = item
    const hasPayload = Array.isArray(payloads) && !!payloads.length
    return html`
      <div class="payload-item">
        <h4>Status code: ${code}</h4>
        ${!hasPayload ? html`<p>No payload defined for this status code</p>` : ''}
        ${hasPayload ? payloads.map((p) => this.payloadTemplate(p)) : ''}
      </div>
    `
  }

  payloadTemplate(payload: IAmfPayload): TemplateResult {
    return html` <api-payload-document .domainId="${payload['@id']}"></api-payload-document> `
  }
}
const instance = new ComponentPage()
instance.render()
