import config from '@assets/js-shop/config';
import { IPrice } from './CartInterfaces';
import { IAddedProduct, IShopDataContext } from '@assets/js-shop/Interfaces';
import { ICartItem, ICurrency, IPhoto, IProduct } from '@assets/js-shop/GraphQLInterfaces';
import { translate as _t } from '@assets/js-shop/ShopUtils';

export class Utils {
   static findProductInCart(
      items: ICartItem[],
      product: ICartItem | IAddedProduct,
      compareNote: boolean = true,
   ): ICartItem {
      const notesEqual = (note1: any, note2: any) => {
         const keys: string[] = Object.getOwnPropertyNames(note1 ?? {}).concat(
            Object.getOwnPropertyNames(note2 ?? {}),
         );
         for (const key of keys) {
            if (!(key in (note1 ?? {}) && key in (note2 ?? {})) || note1[key] != note2[key]) {
               return false;
            }
         }
         return true;
      };

      for (const index in Object.keys(items)) {
         const cartItem = items[index];

         if (
            product.productId === cartItem.productId &&
            (product.variationId ?? null) === (cartItem.variationId ?? null) &&
            (!compareNote || notesEqual(cartItem.note, product.note))
         ) {
            return cartItem;
         }
      }

      return null;
   }

   static printPrice(price: IPrice | number, context: IShopDataContext, round: boolean = false) {
      if (!price) {
         return '';
      }

      // convert price to active currency
      if (typeof price !== 'number') {
         price = Utils.convertPrice(price, context.contexts.currency);
      }

      let rawPrice: number;

      if (typeof price === 'number') {
         rawPrice = price;
      } else {
         rawPrice =
            config.B2BPriceWithoutVat && context.me?.isB2B ? price.withoutVat : price.withVat;
      }

      if (round && context.contexts.currency.roundType) {
         const roundType = context.contexts.currency.roundType;
         const roundConstant = roundType > 0 ? roundType / 100 : Math.abs(roundType);

         const roundFunction = (() => {
            switch (context.contexts.currency.roundDirection) {
               case 'up':
                  return Math.ceil;
               case 'down':
                  return Math.floor;
               default:
                  return Math.round;
            }
         })();

         rawPrice = roundFunction(rawPrice / roundConstant) * roundConstant;
      }

      let precision: number = context.contexts.currency.precision;

      if (precision < 0) {
         // Dvě místa podle potřeby
         precision = /^[+\-]?[0-9]+(\.0+)?$/.test(rawPrice.toString()) ? 0 : 2;
      }

      return (
         rawPrice
            .toFixed(precision)
            .replace(/\B(?=(\d{3})+(?!\d))/g, ' ')
            .replace('.', context.contexts.currency.decimalMark) +
         ' ' +
         context.contexts.currency.symbol
      );
   }

   static printDiscount(discount: number) {
      const rounded = config.cartItemFloorDiscount ? Math.floor(discount) : Math.round(discount);

      return '-' + String(rounded) + '%';
   }

   static printDate(date: Date, format: string = '%d. %m. %Y'): string {
      const getMidnightDate = () => {
         const midnightDate = new Date();
         midnightDate.setHours(0, 0, 0, 0);

         return midnightDate;
      };

      const today = getMidnightDate();
      const tomorrow = getMidnightDate();
      tomorrow.setDate(tomorrow.getDate() + 1);
      const dayAfterTomorrow = getMidnightDate();
      dayAfterTomorrow.setDate(dayAfterTomorrow.getDate() + 2);

      if (date > today && date < tomorrow) {
         return _t('today');
      }

      if (date > tomorrow && date < dayAfterTomorrow) {
         return _t('tomorrow');
      }

      return Utils.formatDate(date, format);
   }

   static printDateLocalePretty(
      date: Date,
      locale: string = null,
      format: string = '%d. %m. %Y',
   ): string {
      const days: { [key: number]: string } = {
         1: 'v pondělí',
         2: 'v úterý',
         3: 've středu',
         4: 've čtvrtek',
         5: 'v pátek',
         6: 'v sobotu',
         0: 'v neděli',
      };

      if (locale !== 'cs') {
         return Utils.formatDate(date, format);
      }

      return days[date.getDay()] + ' ' + Utils.formatDate(date, format);
   }

   static formatDate(date: Date, format: string = '%d. %m. %Y') {
      const replacements: any = {
         '%d': date.getDate(),
         '%m': date.getMonth() + 1,
         '%Y': date.getFullYear(),
      };

      return format.replace(/%\w+/g, (item) => {
         return replacements[item] || item;
      });
   }

   static getImageUrl(photo: IPhoto): string {
      const type = window.wpj.jsShop?.config?.imageType ?? 12; // Hardcoded 12 for components product_cart, viz config_components.php
      const dateUpdate = photo.dateUpdate ? '?' + String(photo.dateUpdate) : '';
      return `/data/tmp/${type}/${photo.id % 10}/${photo.id}_${type}.jpg${dateUpdate}`;
   }

   static printNumber(price: number) {
      return (Math.round(price * 100) / 100).toString().replace('.', ',');
   }

   static printItems(count: number) {
      switch (count) {
         case 1:
            return 'položka';
         case 2:
         case 3:
         case 4:
            return 'položky';
         default:
            return 'položek';
      }
   }

   static roundToStep(num: number, step: number): number {
      return Math.ceil(num / step) * step;
   }

   static convertPrice(price: IPrice, currency: ICurrency): IPrice {
      if (price.currency === undefined) {
         return price;
      }

      if (price.currency.code === currency.code) {
         return price;
      }

      return {
         withVat: (price.withVat * price.currency.rate) / currency.rate,
         withoutVat: (price.withoutVat * price.currency.rate) / currency.rate,
         currency: currency,
      } as IPrice;
   }

   static countProducts(items: ICartItem[]): number {
      return items.reduce((acc: number, obj: ICartItem) => {
         return acc + obj.pieces;
      }, 0);
   }

}
