declare global {
   interface Window {
      dataLayer: Record<string, any>[];
   }
}

function getArrayOfEventsFromDataLayer(dataLayer: Record<string, any>[]) {
   return Cypress._.map(dataLayer, (o) => Cypress._.pick(o, 'event'));
}

function getEventFromDataLayer(dataLayer: Record<string, any>[], event: string) {
   return Cypress._.find(dataLayer, (o) => o.event === event);
}

export function getCelenkaEcommerceItem() {
   return {
      item_id: 104,
      product_id: 104,
      ean: '',
      item_code: 'XY264',
      product_code: 'XY264',
      has_variations: false,
      variation_ids: [],
      variation_id: null,
      variation_code: null,
      item_variant: null,
      sold_out: null,
      variation_codes: [],
      category_main: [
         { id: 386, name: 'Oblečení' },
         { id: 388, name: 'Doplňky' },
         { id: 393, name: 'Čepice' },
      ],
      item_brand: 'wpj',
      campaigns: [],
      item_name: 'Čelenka Mountains black&white',
      tax: 21,
      price: 149,
      price_with_tax: 149,
      price_without_tax: 123.14,
      price_tax: 25.86,
      price_without_discount: 149,
      discount: 0,
      has_discount: false,
      availability: 'skladem',
      url: '',
      image_url: '',
      category_current: [
         { id: 386, name: 'Oblečení' },
         { id: 388, name: 'Doplňky' },
         { id: 393, name: 'Čepice' },
      ],
      quantity: null,
   };
}

export function dataLayerContains(target: Record<string, any>) {
   expect(window.dataLayer).to.contain(target);
}

export function dataLayerContainsEvent(event: string) {
   cy.window()
      .then((win) => {
         return getArrayOfEventsFromDataLayer(win.dataLayer);
      })
      .should('deep.include', { event });
}

export function dataLayerContainsEcommerceItem(ecommerceItem: Record<string, any>) {
   cy.window().then((win) => {
      const itemFound = win.dataLayer.some((layerItem) =>
         layerItem.ecommerce?.items.some((item: Record<string, any>) =>
            Cypress._.isEqual({
               ...item,
               url: '',
               image_url: '',
            }, ecommerceItem),
         ),
      );
      expect(itemFound, `Item ${JSON.stringify(ecommerceItem)} not found in any ecommerce items array \ndataLayer: ${JSON.stringify(win.dataLayer)}`).to.be.true;
   });
}

export function dataLayerEventContainsEcommerceItem(
   event: string,
   ecommerceItem: Record<string, any>,
) {
   cy.window().then((win) => {
      const eventObject = getEventFromDataLayer(win.dataLayer, event);
      const itemFound = eventObject.ecommerce?.items.some((item: Record<string, any>) => {
         return Cypress._.isEqual({
            ...item,
            url: '',
            image_url: '',
         }, ecommerceItem);
      });
      expect(itemFound, `Item ${JSON.stringify(ecommerceItem)} not found in ecommerce of ${event} event. \neventObject: ${JSON.stringify(eventObject)}`).to.be.true;
   });
}

export function dataLayerEventEcommerceContainsKey(event: string, key: string) {
   cy.window().then((win) => {
      const eventObject = getEventFromDataLayer(win.dataLayer, event);
      expect(Object.prototype.hasOwnProperty.call(eventObject.ecommerce, key), `Event ${event} doesn't have ${key} key. \neventObject: ${JSON.stringify(eventObject)}`).to.be.true;
   });
}

export function checkUserInfoPosition() {
   cy.window().then((win) => {
      const events = Cypress._.filter(
         getArrayOfEventsFromDataLayer(win.dataLayer),
         (event) => {
            return Object.prototype.hasOwnProperty.call(event, 'event') && !event.event.includes('gtm');
         },
      );
      const consentIndex = Cypress._.findIndex(events, { event: 'consent_default' });
      const userInfoIndex = Cypress._.findIndex(events, { event: 'user_info' });

      // user info je hned po consentu
      expect(userInfoIndex).to.be.eq(consentIndex + 1, `User info is in wrong position, \nall events: ${JSON.stringify(events)}`);
   });
}

export function dataLayerEventEcommerceContainsKeyAndValue(event: string, key: string, value: string) {
   cy.window().then((win) => {
      const eventObject = getEventFromDataLayer(win.dataLayer, event);

      expect(Object.prototype.hasOwnProperty.call(eventObject.ecommerce, key), `${event} is missing the ${key} property, \neventObject: ${JSON.stringify(eventObject)}`).to.be.true;
      expect(eventObject.ecommerce[key]).to.be.eq(value, `${key} in event ${event} does not have expected value ${value}`);
   });
}

export function checkDataLayerEventHasCorrectPositionsForEcommerceItems(event: string) {
   cy.window().then((win) => {
      const eventObject = getEventFromDataLayer(win.dataLayer, event);

      expect(eventObject.ecommerce.items[0].position).to.be.eq(1, `Item at position 0 has wrong position value, \neventObject: ${JSON.stringify(eventObject)}`);
      expect(eventObject.ecommerce.items[1].position).to.be.eq(2, `Item at position 1 has wrong position value, \neventObject: ${JSON.stringify(eventObject)}`);
   });
}

export function checkDataLayerEcommerceItemHasCorrectPosition(event: string, index: number, position: number) {
   cy.window().then((win) => {
      const eventObject = getEventFromDataLayer(win.dataLayer, event);

      expect(eventObject.ecommerce.items[index].position).to.be.eq(position, `Item at index ${index} in event ${event} has wrong position, \neventObject: ${JSON.stringify(eventObject)}`);
   });
}
