import { fixture, assert, aTimeout, nextFrame, html } from '@open-wc/testing'
import sinon from 'sinon'
import { AmfDefinitions, ApiDefinitions, IApiKeyAuthorization } from '@api-client/core/browser.js'
import { AmfLoader } from '../AmfLoader.js'
import AmfApiKey from '../../../src/elements/amf/authorization/AmfApiKey.js'
import Input from '../../../src/md/input/Input.js'
import '../../../src/define/amf/authorization/amf-apikey-authorization.js'

describe.skip('Api Key authorization', () => {
  async function methodFixture(security?: ApiDefinitions.IApiParametrizedSecurityScheme): Promise<AmfApiKey> {
    return fixture(html`<amf-apikey-authorization .security="${security}"></amf-apikey-authorization>`)
  }

  let store: AmfLoader
  let model: AmfDefinitions.IAmfDocument
  before(async () => {
    store = new AmfLoader()
    model = await store.getGraph('api-keys')
  })

  describe('initialization', () => {
    it('can be initialized in a template with model', async () => {
      const operation = store.getOperation(model, '/query', 'get')
      const element = await methodFixture(operation.security[0])
      await aTimeout(0)
      await element.updateComplete
      assert.ok(element)
    })
  })

  function getApiParametrizedSecurityScheme(
    path: string,
    method: string
  ): ApiDefinitions.IApiParametrizedSecurityScheme {
    const operation = store.getOperation(model, path, method)
    return operation.security[0].schemes[0]
  }

  describe('content rendering', () => {
    it('renders headers', async () => {
      const scheme = getApiParametrizedSecurityScheme('/header', 'get')
      const element = await methodFixture(scheme)
      const nodes = element.shadowRoot!.querySelectorAll(`.form-input[data-binding="header"]`)
      assert.lengthOf(nodes, 1)
    })

    it('renders query parameters', async () => {
      const scheme = getApiParametrizedSecurityScheme('/query', 'get')
      const element = await methodFixture(scheme)
      const nodes = element.shadowRoot!.querySelectorAll(`.form-input[data-binding="query"]`)
      assert.lengthOf(nodes, 1)
    })

    it('renders cookies', async () => {
      const scheme = getApiParametrizedSecurityScheme('/cookie', 'get')
      const element = await methodFixture(scheme)
      const nodes = element.shadowRoot!.querySelectorAll(`.form-input[data-binding="cookie"]`)
      assert.lengthOf(nodes, 1)
    })

    // it('renders multiple schemes', async () => {
    //   const scheme = await getApiParametrizedSecurityScheme('/junction', 'get');
    //   const element = await basicFixture(scheme);
    //   const nodes = element.shadowRoot!.querySelectorAll(`.form-input`);
    //   assert.lengthOf(nodes, 2);
    // });

    it('renders scheme title', async () => {
      const scheme = getApiParametrizedSecurityScheme('/header', 'get')
      const element = await methodFixture(scheme)
      const node = element.shadowRoot!.querySelector(`.subtitle`) as HTMLElement
      const result = (node.textContent as string).trim()
      assert.equal(result, 'Scheme: Api Key')
    })
  })

  describe('change notification', () => {
    it('notifies when value change', async () => {
      const scheme = getApiParametrizedSecurityScheme('/header', 'get')
      const element = await methodFixture(scheme)
      const input = element.shadowRoot!.querySelector(`[name="client_secret"]`) as Input
      input.value = 'test'
      const spy = sinon.spy()
      element.addEventListener('change', spy)
      input.dispatchEvent(new CustomEvent('change'))
      assert.isTrue(spy.called)
    })

    it('notifies when cookie value change', async () => {
      const scheme = getApiParametrizedSecurityScheme('/cookie', 'get')
      const element = await methodFixture(scheme)
      const input = element.shadowRoot!.querySelector(`[name="client_secret"]`) as Input
      input.value = 'test'
      const spy = sinon.spy()
      element.addEventListener('change', spy)
      input.dispatchEvent(new CustomEvent('change'))
      assert.isTrue(spy.called)
    })
  })

  describe('updateQueryParameter()', () => {
    it('updates query parameter value', async () => {
      const scheme = getApiParametrizedSecurityScheme('/query', 'get')
      const element = await methodFixture(scheme)
      element.updateQueryParameter('client_id', 'test')
      const result = element.serialize() as IApiKeyAuthorization
      assert.equal((result.query as Record<string, string>).client_id, 'test')
    })
  })

  describe('updateHeader()', () => {
    it('updates header value', async () => {
      const scheme = getApiParametrizedSecurityScheme('/header', 'get')
      const element = await methodFixture(scheme)
      element.updateHeader('client_secret', 'testHeader')
      const result = element.serialize() as IApiKeyAuthorization
      assert.equal((result.header as Record<string, string>).client_secret, 'testHeader')
    })
  })

  describe('updateCookie()', () => {
    it('updates cookie value', async () => {
      const scheme = getApiParametrizedSecurityScheme('/cookie', 'get')
      const element = await methodFixture(scheme)
      element.updateCookie('client_secret', 'secret')
      const result = element.serialize() as IApiKeyAuthorization
      assert.equal((result.cookie as Record<string, string>).client_secret, 'secret')
    })
  })

  describe('checkValidity()', () => {
    let element: AmfApiKey
    beforeEach(async () => {
      const scheme = getApiParametrizedSecurityScheme('/query', 'get')
      element = await methodFixture(scheme)
    })

    it('returns false when required field is empty', () => {
      const result = element.checkValidity()
      assert.isFalse(result)
    })

    it('returns true when valid', async () => {
      const input = element.shadowRoot!.querySelector(`[name="client_id"]`) as Input
      input.value = 'test'
      input.dispatchEvent(new CustomEvent('change'))
      await nextFrame()
      const result = element.checkValidity()
      assert.isTrue(result)
    })
  })

  describe('a11y', () => {
    it('is accessible for custom fields (headers and qp)', async () => {
      const scheme = getApiParametrizedSecurityScheme('/query', 'get')
      const element = await methodFixture(scheme)
      await assert.isAccessible(element)
    })
  })
})
