import { fixture, assert, nextFrame, html } from '@open-wc/testing'
import { AmfDefinitions, ApiDefinitions, IOauth2GrantType } from '@api-client/core/browser.js'
import { AmfLoader } from '../AmfLoader.js'
import AmfOauth2 from '../../../src/elements/amf/authorization/AmfOauth2.js'
import '../../../src/define/amf/authorization/amf-oauth2-authorization.js'

describe.skip('OAuth 2', () => {
  async function methodFixture(security?: ApiDefinitions.IApiParametrizedSecurityScheme): Promise<AmfOauth2> {
    return fixture(html`<amf-oauth2-authorization .security="${security}"></amf-oauth2-authorization>`)
  }

  async function basicFixture(): Promise<AmfOauth2> {
    return fixture(html`<amf-oauth2-authorization></amf-oauth2-authorization>`)
  }

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

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

  describe('OAS grant types (flows)', () => {
    let element: AmfOauth2

    beforeEach(async () => {
      const scheme = getApiParametrizedSecurityScheme('/pets', 'patch')
      element = await methodFixture(scheme)
    })

    it('renders all defined grant types', () => {
      const gt = element.grantTypes as IOauth2GrantType[]
      const implicit = gt.find((i) => i.type === 'implicit')
      const code = gt.find((i) => i.type === 'authorization_code')
      const credentials = gt.find((i) => i.type === 'client_credentials')
      const password = gt.find((i) => i.type === 'password')
      assert.ok(implicit, 'has the implicit grant type')
      assert.ok(code, 'has the authorization_code grant type')
      assert.ok(credentials, 'has the client_credentials grant type')
      assert.ok(password, 'has the password grant type')
    })

    it('initializes first flow by default', () => {
      assert.equal(element.config.grantType, 'implicit')
    })

    it('applies configuration when initializing', () => {
      assert.equal(
        element.config.authorizationUri,
        'https://api.example.com/oauth2/authorize',
        'authorizationUri is set'
      )
      assert.deepEqual(element.config.scopes, ['read_pets', 'write_pets'], 'scopes is set')
    })

    it('applies configuration on grant type change', async () => {
      element.config.grantType = 'authorization_code'
      await nextFrame()
      assert.equal(element.config.authorizationUri, '/oauth2/authorize', 'authorizationUri is set')
      assert.equal(element.config.accessTokenUri, '/oauth2/token', 'accessTokenUri is set')
      assert.deepEqual(element.config.scopes, ['all'], 'scopes is set')
    })

    it('restores configuration when grant type is selected', async () => {
      element = await basicFixture()
      element.config.grantType = 'authorization_code'
      await nextFrame()
      element.security = getApiParametrizedSecurityScheme('/pets', 'patch')
      await nextFrame()
      assert.equal(element.config.grantType, 'authorization_code', 'grantType is not changed')
      assert.equal(element.config.authorizationUri, '/oauth2/authorize', 'authorizationUri is set')
      assert.equal(element.config.accessTokenUri, '/oauth2/token', 'accessTokenUri is set')
      assert.deepEqual(element.config.scopes, ['all'], 'scopes is set')
    })

    it('applies client credentials grant type', async () => {
      element.config.grantType = 'client_credentials'
      await nextFrame()
      assert.equal(element.config.accessTokenUri, '/oauth2/token-client', 'accessTokenUri is set')
      assert.include(element.config.scopes as string[], 'write_pets', 'has write_pets scope')
      assert.include(element.config.scopes as string[], 'read_pets', 'has read_pets scope')
    })

    it('applies password grant type', async () => {
      element.config.grantType = 'password'
      await nextFrame()
      assert.equal(element.config.accessTokenUri, '/oauth2/token-password', 'accessTokenUri is set')
      assert.deepEqual(element.config.scopes, ['read_pets'], 'scopes is set')
    })
  })
})
