import { assert, fixture, html } from '@open-wc/testing';
import sinon from 'sinon';
import { AmfEvents, AmfEventTypes, TelemetryEventDetail, TelemetryExceptionDetail, TelemetryScreenViewDetail, TelemetrySocialDetail, TelemetryTimingDetail } from  '../../../src/index.js';

describe('Events', () => {
  async function etFixture(): Promise<HTMLDivElement> {
    return fixture(html`<div></div>`);
  }

  describe('Telemetry', () => {
    describe('view()', () => {
      const screenName = 'test-screen';

      it('dispatches the event', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.view, spy);
        AmfEvents.Telemetry.view(et, screenName);
        assert.isTrue(spy.calledOnce);
      });

      it('the event has screen name on the detail', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.view, spy);
        AmfEvents.Telemetry.view(et, screenName);
        const info = (spy.args[0][0].detail) as TelemetryScreenViewDetail;
        assert.equal(info.screenName, screenName);
      });

      it('the event has custom configuration', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        const custom = {
          customMetrics: [{ index: 1, value: 1 }],
          customDimensions: [{ index: 1, value: 'test' }],
        };
        et.addEventListener(AmfEventTypes.Telemetry.view, spy);
        AmfEvents.Telemetry.view(et, screenName, custom);
        const info = (spy.args[0][0].detail) as TelemetryScreenViewDetail;
        assert.deepEqual(info.customMetrics, custom.customMetrics, 'has customMetrics');
        assert.deepEqual(info.customDimensions, custom.customDimensions, 'has customDimensions');
      });
    });

    describe('event()', () => {
      const init = { 
        category: 'e-cat',
        action: 'e-act',
        label: 'e-label',
        value: 1,
      };

      it('dispatches the event', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.event, spy);
        AmfEvents.Telemetry.event(et, init);
        assert.isTrue(spy.calledOnce);
      });

      it('the event has the detail object', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.event, spy);
        AmfEvents.Telemetry.event(et, init);
        const info = (spy.args[0][0].detail) as TelemetryEventDetail;
        assert.deepEqual(info, init);
      });
    });

    describe('exception()', () => {
      const description = 'event-exception';
      const fatal = true;

      it('dispatches the event', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.exception, spy);
        AmfEvents.Telemetry.exception(et, description);
        assert.isTrue(spy.calledOnce);
      });

      it('the event has the description property', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.exception, spy);
        AmfEvents.Telemetry.exception(et, description);
        const info = (spy.args[0][0].detail) as TelemetryExceptionDetail;
        assert.equal(info.description, description);
      });

      it('the event has the fatal property', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.exception, spy);
        AmfEvents.Telemetry.exception(et, description, fatal);
        const info = (spy.args[0][0].detail) as TelemetryExceptionDetail;
        assert.equal(info.fatal, true);
      });

      it('the event has the custom configuration', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        const custom = {
          customMetrics: [{ index: 1, value: 1 }],
          customDimensions: [{ index: 1, value: 'test' }],
        };
        et.addEventListener(AmfEventTypes.Telemetry.exception, spy);
        AmfEvents.Telemetry.exception(et, description, false, custom);
        const info = (spy.args[0][0].detail) as TelemetryExceptionDetail;
        assert.deepEqual(info.customMetrics, custom.customMetrics, 'has customMetrics');
        assert.deepEqual(info.customDimensions, custom.customDimensions, 'has customDimensions');
      });
    });

    describe('social()', () => {
      const init = { 
        network: 'e-network',
        action: 'e-action',
        target: 'e-target',
      };

      it('dispatches the event', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.social, spy);
        AmfEvents.Telemetry.social(et, init.network, init.action, init.target);
        assert.isTrue(spy.calledOnce);
      });

      it('the event has the detail object', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.social, spy);
        AmfEvents.Telemetry.social(et, init.network, init.action, init.target);
        const info = (spy.args[0][0].detail) as TelemetrySocialDetail;
        assert.deepEqual(info, init);
      });

      it('the event has custom configuration', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        const custom = {
          customMetrics: [{ index: 1, value: 1 }],
          customDimensions: [{ index: 1, value: 'test' }],
        };
        et.addEventListener(AmfEventTypes.Telemetry.social, spy);
        AmfEvents.Telemetry.social(et, init.network, init.action, init.target, custom);
        const info = (spy.args[0][0].detail) as TelemetrySocialDetail;
        assert.deepEqual(info, { ...init, ...custom });
      });
    });

    describe('timing()', () => {
      const init = { 
        category: 'e-category',
        variable: 'e-variable',
        value: 100,
        label: 'e-label',
      };

      it('dispatches the event', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.timing, spy);
        AmfEvents.Telemetry.timing(et, init.category, init.variable, init.value, init.label);
        assert.isTrue(spy.calledOnce);
      });

      it('the event has the detail object', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        et.addEventListener(AmfEventTypes.Telemetry.timing, spy);
        AmfEvents.Telemetry.timing(et, init.category, init.variable, init.value, init.label);
        const info = spy.args[0][0].detail as TelemetryTimingDetail;
        assert.deepEqual(info, init);
      });

      it('the event has custom configuration', async () => {
        const et = await etFixture();
        const spy = sinon.spy();
        const custom = {
          customMetrics: [{ index: 1, value: 1 }],
          customDimensions: [{ index: 1, value: 'test' }],
        };
        et.addEventListener(AmfEventTypes.Telemetry.timing, spy);
        AmfEvents.Telemetry.timing(et, init.category, init.variable, init.value, init.label, custom);
        const info = spy.args[0][0].detail as TelemetryTimingDetail;
        assert.deepEqual(info, { ...init, ...custom });
      });
    });
  });
});
