/* eslint-disable @typescript-eslint/ban-ts-comment */
import { html, fixture, assert, nextFrame } from '@open-wc/testing';
import sinon from 'sinon';
import { AmfDefinitions, ApiDefinitions, IApiKeyAuthorization, IBearerAuthorization } from '@api-client/core/build/browser.js';
import { AmfLoader } from "../AmfLoader.js";
import ApiAuthorizationEditorElement, { SecurityMethods } from '../../../src/elements/amf/ApiAuthorizationEditor.element.js';
import '../../../src/define/amf/api-authorization-editor.js';

describe.skip('ApiAuthorizationEditorElement OAS tests', () => {
  async function basicFixture(security?: ApiDefinitions.IApiSecurityRequirement): Promise<ApiAuthorizationEditorElement> {
    const element = (await fixture(html`<api-authorization-editor
      .security="${security}"
    ></api-authorization-editor>`));
    return element as ApiAuthorizationEditorElement;
  }

  let store: AmfLoader;
  before(async () => {
    store = new AmfLoader();
  });

  function getSecurityRequirement(model: AmfDefinitions.IAmfDocument, path: string, method: string): ApiDefinitions.IApiSecurityRequirement {
    const operation = store.getOperation(model, path, method);
    return operation.security[0];
  }

  describe('Compact model', () => {
    describe('Single vs multiple', () => {
      let model: AmfDefinitions.IAmfDocument;
      before(async () => {
        model = await store.getGraph('secured-unions');
      });
  
      describe(`Single method`, () => {
        let element: ApiAuthorizationEditorElement;
        
        beforeEach(async () => {
          const security = getSecurityRequirement(model, '/single', 'get');
          element = await basicFixture(security);
        });
  
        it('has a single method definition', () => {
          const methods = element.methods as SecurityMethods;
          assert.lengthOf(methods.types, 1);
        });
  
        it('renders a single method', () => {
          const nodes = element.shadowRoot!.querySelectorAll('api-authorization-method');
          assert.lengthOf(nodes, 1);
        });
      });
  
      describe(`Multiple methods`, () => {
        let element: ApiAuthorizationEditorElement;
  
        beforeEach(async () => {
          const security = getSecurityRequirement(model, '/and-and-or-union', 'get');
          element = await basicFixture(security);
        });
  
        it('has all methods definitions', () => {
          const methods = element.methods as SecurityMethods;
          assert.lengthOf(methods.types, 2);
        });
  
        it('renders editors for each method', () => {
          const nodes = element.shadowRoot!.querySelectorAll('api-authorization-method');
          assert.lengthOf(nodes, 2);
        });
      });
    });
  
    describe('Api Key method', () => {
      let model: AmfDefinitions.IAmfDocument;
      before(async () => {
        model = await store.getGraph('api-keys');
      });
  
      describe(`Basic tests`, () => {
        let element: ApiAuthorizationEditorElement;
        
        beforeEach(async () => {
          const security = getSecurityRequirement(model, '/query', 'get');
          element = await basicFixture(security);
        });
  
        it('has "types" in the authorization object', () => {
          const methods = element.methods as SecurityMethods;
          const { types } = methods;
          assert.deepEqual(types, ['Api Key']);
        });
  
        it('has "schemes" in the authorization object', () => {
          const methods = element.methods as SecurityMethods;
          const { schemes } = methods;
          assert.typeOf(schemes[0], 'object');
        });
  
        it('notifies changes when panel value change', () => {
          const form = element.shadowRoot!.querySelector('amf-apikey-authorization')!;
          const spy = sinon.spy();
          element.addEventListener('change', spy);
          form.updateQueryParameter('client_id', 'test')
          form.dispatchEvent(new CustomEvent('change'));
          assert.isTrue(spy.called);
        });
  
        // it.skip('element is not invalid without required values', () => {
        //   const result = element.validate();
        //   assert.isFalse(result, 'validation result is false');
        //   assert.isNotTrue(element.invalid, 'is not invalid');
        // });
  
        it('element is valid with required values', async () => {
          const form = element.shadowRoot!.querySelector('amf-apikey-authorization')!;
          form.updateQueryParameter('client_id', 'test');
          form.dispatchEvent(new CustomEvent('change'));
          await nextFrame();
          const result = element.validate();
          assert.isTrue(result, 'validation result is true');
          assert.isFalse(element.invalid, 'is not invalid');
        });
  
        it('serializes the settings', async () => {
          const form = element.shadowRoot!.querySelector('amf-apikey-authorization')!;
          form.updateQueryParameter('client_id', 'test');
          form.dispatchEvent(new CustomEvent('change'));
          await nextFrame();
          const auth = element.serialize();
          const [result] = auth;
          assert.equal(result.type, 'api key', 'auth has type');
          assert.equal(result.valid, true, 'auth is valid');
          assert.equal(result.enabled, true, 'auth is enabled');
          assert.typeOf(result.config, 'object', 'has auth config');
          const cnf = result.config as IApiKeyAuthorization;
          assert.equal((cnf.query as Record<string, string>).client_id, 'test', 'has config.query.client_id');
        });
      });

      describe(`Junction of methods`, () => {
        let element: ApiAuthorizationEditorElement;
        
        beforeEach(async () => {
          const security = getSecurityRequirement(model, '/junction', 'get');
          element = await basicFixture(security);
        });

        it('renders multiple methods', () => {
          const nodes = element.shadowRoot!.querySelectorAll('amf-apikey-authorization');
          assert.lengthOf(nodes, 2);
        });

        it('renders labels above the editor', () => {
          const nodes = element.shadowRoot!.querySelectorAll('amf-apikey-authorization');
          
          assert.equal(((nodes[0].previousElementSibling as HTMLElement).textContent as string).trim(), 'clientQuery');
          assert.equal(((nodes[1].previousElementSibling as HTMLElement).textContent as string).trim(), 'clientMulti');
        });

        it('serializes both methods', async () => {
          const forms = element.shadowRoot!.querySelectorAll('amf-apikey-authorization');
          forms[0].updateQueryParameter('client_id', 'test-param');
          forms[1].updateHeader('client_multi', 'test-multi');
          forms[0].dispatchEvent(new CustomEvent('change'));
          forms[1].dispatchEvent(new CustomEvent('change'));
          await nextFrame();
          const result = element.serialize();
          assert.lengthOf(result, 2, 'has 2 items')
          const [s1, s2] = result;
          // @ts-ignore
          assert.deepEqual(s2.config.header, { client_multi: 'test-multi' }, 'has headers');
          // @ts-ignore
          assert.deepEqual(s1.config.query, { client_id: 'test-param' }, 'has params');
        });
      });
    });
  
    describe('Bearer method', () => {
      let model: AmfDefinitions.IAmfDocument;
      before(async () => {
        model = await store.getGraph('oas-bearer');
      });
  
      describe(`Basic tests`, () => {
        let element: ApiAuthorizationEditorElement;
        
        beforeEach(async () => {
          const security = getSecurityRequirement(model, '/bearer', 'get');
          element = await basicFixture(security);
        });
  
        it('has "types" in the authorization object', () => {
          const methods = element.methods as SecurityMethods;
          const { types } = methods;
          assert.deepEqual(types, ['bearer']);
        });
  
        it('has "schemes" in the authorization object', () => {
          const methods = element.methods as SecurityMethods;
          const { schemes } = methods;
          assert.typeOf(schemes[0], 'object');
        });
  
        it('notifies changes when panel value change', () => {
          const form = element.shadowRoot!.querySelector('amf-bearer-authorization')!;
          const spy = sinon.spy();
          element.addEventListener('change', spy);
          form.config.token = 'test';
          form.dispatchEvent(new CustomEvent('change'));
          assert.isTrue(spy.called);
        });
  
        it('element is invalid without required values', () => {
          const result = element.validate();
          assert.isFalse(result, 'validation result is false');
          assert.isTrue(element.invalid, 'is invalid');
        });
  
        it('element is valid with required values', async () => {
          const form = element.shadowRoot!.querySelector('amf-bearer-authorization')!;
          form.config.token = 'test';
          form.dispatchEvent(new CustomEvent('change'));
          await nextFrame();
          const result = element.validate();
          assert.isTrue(result, 'validation result is true');
          assert.isFalse(element.invalid, 'is not invalid');
        });
  
        it('creates params with serialize()', async () => {
          const form = element.shadowRoot!.querySelector('amf-bearer-authorization')!;
          form.config.token = 'test';
          form.dispatchEvent(new CustomEvent('change'));
          await nextFrame();
          const [result] = element.serialize();
          const cnf = result.config as IBearerAuthorization;
          assert.deepEqual(cnf, {
            token: 'test',
          }, 'has the configuration');
        });
      });
    });
  });
  
});
