import { html, fixture, assert, oneEvent } from '@open-wc/testing'
import { IBearerAuthorization, IRequestAuthorization, RequestAuthorization } from '@api-client/core/browser.js'
import { Authorization } from '../../../src/elements/authorization/ui/Authorization.js'
import Input from '../../../src/md/input/Input.js'
import '../../../src/define/authorization/bearer-authorization.js'

describe('Bearer method', () => {
  const tokenSelector = 'ui-filled-text-field[name="token"]'
  const token = 'test-token'

  async function basicFixture(auth?: IRequestAuthorization): Promise<Authorization> {
    return fixture(html`<bearer-authorization .authorization="${auth}"></bearer-authorization>`)
  }

  describe('DOM rendering', () => {
    let element: Authorization
    let form: HTMLFormElement
    beforeEach(async () => {
      const auth = RequestAuthorization.fromTypedConfig('bearer', {}).toJSON()
      element = await basicFixture(auth)
      form = element.shadowRoot!.querySelector('form')!
    })

    it('has form in the DOM', async () => {
      assert.ok(form)
    })

    it('has form has autocomplete', async () => {
      assert.equal(form.getAttribute('autocomplete'), 'on')
    })

    it('form has token input', async () => {
      const input = form.querySelector(tokenSelector)
      assert.ok(input)
    })

    it('token is required', async () => {
      const input = form.querySelector(tokenSelector) as Input
      assert.isTrue(input.required)
    })

    it('token has invalid label', async () => {
      const input = form.querySelector(tokenSelector) as Input
      assert.equal(input.invalidText, 'Token is required', 'Token has the invalidText')
    })

    it('has no other inputs', () => {
      const controls = form.querySelectorAll('ui-filled-text-field')
      assert.lengthOf(controls, 1)
    })
  })

  describe('change notification', () => {
    let element: Authorization
    beforeEach(async () => {
      const auth = RequestAuthorization.fromTypedConfig('bearer', {}).toJSON()
      element = await basicFixture(auth)
    })

    it('notifies when token changes', async () => {
      const input = element.shadowRoot!.querySelector(tokenSelector) as Input
      setTimeout(() => {
        input.value = 'test'
        input.dispatchEvent(new CustomEvent('change'))
      })
      const e = await oneEvent(element, 'change')
      assert.ok(e)
    })
  })

  describe('updating the model', () => {
    let element: Authorization
    beforeEach(async () => {
      const auth = RequestAuthorization.fromTypedConfig('bearer', {
        token,
      }).toJSON()
      element = await basicFixture(auth)
    })

    it('updates the token from user input', () => {
      const input = element.shadowRoot!.querySelector(tokenSelector) as Input
      input.value = 'test'
      input.dispatchEvent(new Event('change'))
      const config = element.authorization!.config as IBearerAuthorization
      assert.equal(config.token, 'test')
    })
  })

  describe('data restoration', () => {
    let element: Authorization
    beforeEach(async () => {
      const auth = RequestAuthorization.fromTypedConfig('bearer', {
        token,
      }).toJSON()
      element = await basicFixture(auth)
    })

    it('has the value on the token filed', () => {
      const input = element.shadowRoot!.querySelector(tokenSelector) as Input
      assert.equal(input.value, token)
    })
  })

  describe('validation', () => {
    let element: Authorization
    beforeEach(async () => {
      const auth = RequestAuthorization.fromTypedConfig('bearer', {}).toJSON()
      element = await basicFixture(auth)
    })

    it('is not valid without the token', () => {
      const result = element.checkValidity()
      assert.isFalse(result)
    })

    it('is valid with the token', async () => {
      ;(element.authorization!.config as IBearerAuthorization).token = token
      element.requestUpdate()
      await element.updateComplete
      const result = element.checkValidity()
      assert.isTrue(result)
    })
  })

  describe('a11y', () => {
    it('is accessible without the model', async () => {
      const element = await basicFixture()
      await assert.isAccessible(element)
    })

    it('is accessible when empty', async () => {
      const auth = RequestAuthorization.fromTypedConfig('bearer', {}).toJSON()
      const element = await basicFixture(auth)
      await assert.isAccessible(element)
    })

    it('is accessible with values', async () => {
      const auth = RequestAuthorization.fromTypedConfig('bearer', { token }).toJSON()
      const element = await basicFixture(auth)
      await assert.isAccessible(element)
    })
  })
})
