import { fixture, assert, aTimeout, nextFrame, html } from '@open-wc/testing';
import sinon from 'sinon';
import { AmfDefinitions, ApiDefinitions, IPassThroughAuthorization } from '@api-client/core/build/browser.js';
import { AmfLoader } from "../AmfLoader.js";
import AmfPassThrough from '../../../src/elements/amf/authorization/AmfPassThrough.js';
import Input from '../../../src/ui/input/Input.js';
import '../../../src/define/amf/authorization/amf-passthrough-authorization.js';

describe.skip('Pass Through authorization', () => {
  async function methodFixture(security?: ApiDefinitions.IApiParametrizedSecurityScheme): Promise<AmfPassThrough> {
    return (fixture(html`<amf-passthrough-authorization .security="${security}"></amf-passthrough-authorization>`));
  }

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

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

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

  describe('content rendering', () => {
    it('renders headers', async () => {
      const scheme = getApiParametrizedSecurityScheme('/passthrough', '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('/passthrough', 'get');
      const element = await methodFixture(scheme);
      const nodes = element.shadowRoot!.querySelectorAll(`[data-binding="query"]`);
      assert.lengthOf(nodes, 2);
    });

    it('renders scheme title', async () => {
      const scheme = getApiParametrizedSecurityScheme('/passthrough', '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: passthrough');
    });

    it('renders scheme docs toggle button', async () => {
      const scheme = getApiParametrizedSecurityScheme('/passthrough', 'get');
      const element = await methodFixture(scheme);
      const node = element.shadowRoot!.querySelector(`.subtitle .hint-icon`);
      assert.ok(node);
    });

    it('ignores other security schemes', async () => {
      const scheme = getApiParametrizedSecurityScheme('/basic', 'get');
      const element = await methodFixture(scheme);
      const nodes = element.shadowRoot!.querySelectorAll(`.form-input`);
      assert.lengthOf(nodes, 0);
    });
  });

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

    it('notifies when selection change', async () => {
      const scheme = getApiParametrizedSecurityScheme('/passthrough', 'get');
      const element = await methodFixture(scheme);
      const input = element.shadowRoot!.querySelector(`[name="debugTokenParam"]`) as HTMLElement;
      const option = input.querySelector(`[data-value="Log"]`) as HTMLElement;
      const spy = sinon.spy();
      element.addEventListener('change', spy);
      option.click();
      await nextFrame();
      assert.isTrue(spy.called);
    });
  });

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

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

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

  describe('Support for queryString property', () => {
    let element: AmfPassThrough;

    beforeEach(async () => {
      const scheme = getApiParametrizedSecurityScheme('/passthrough-query-string', 'get');
      element = await methodFixture(scheme);
    });

    it('renders input filled for NodeShape', () => {
      const nodes = element.shadowRoot!.querySelectorAll(`.form-input[data-binding="query"]`);
      assert.lengthOf(nodes, 2);
    });
  });

  describe('checkValidity()', () => {
    let element: AmfPassThrough;

    beforeEach(async () => {
      const scheme = getApiParametrizedSecurityScheme('/passthrough-query-string', 'get');
      element = await methodFixture(scheme);
    });

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

    it('renders optional field valid', async () => {
      element.checkValidity();
      await nextFrame();
      const input = (element.shadowRoot!.querySelector(`[name="queryStringProperty2"]`)) as Input;
      assert.isUndefined(input.invalid);
    });

    it('returns true when valid', async () => {
      const input = (element.shadowRoot!.querySelector(`[name="queryStringProperty1"]`)) as Input;
      input.value = '123';
      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('/passthrough', 'get');
      const element = await methodFixture(scheme);
      await assert.isAccessible(element);
    });
  });
});
