import { Controller } from '@hotwired/stimulus';
import { type Component, getComponent } from '@symfony/ux-live-component';
import { DISABLE_BUY_FORM_ADD_TO_CART, ENABLE_BUY_FORM_ADD_TO_CART, RELOAD_NOTE_BUY_FORM } from '@assets/js-multisets/common/constants/eventTypes';
import { IAddedProduct } from '@assets/js-shop/Interfaces';
import { initializeTooltips } from '@assets/components/tooltips';

export default class extends Controller<HTMLDivElement> {
   static targets = ['addToCartButton', 'giftCardPrice'];
   static values = {
      initListeners: Boolean,
      hasVariations: Boolean,
      controlButtonByListeners: Boolean,

      productId: Number,
      variationId: Number,
   };

   private component: Component;

   declare initListenersValue: boolean;
   declare productIdValue: number;
   declare variationIdValue: number | null;
   declare hasVariationsValue: boolean;

   declare controlButtonByListenersValue: boolean;
   private buttonStateByListener: boolean;

   declare hasAddToCartButtonTarget: boolean;
   declare addToCartButtonTarget: HTMLButtonElement;

   declare hasGiftCardPriceTarget: boolean;
   declare giftCardPriceTarget: HTMLElement;

   async initialize() {
      this.component = await getComponent(this.element as HTMLElement);

      if (this.initListenersValue) {
         this.buttonStateByListener = false;
         document.addEventListener(DISABLE_BUY_FORM_ADD_TO_CART, () => { this.disableAddToCartButton(); this.buttonStateByListener = false; });
         document.addEventListener(ENABLE_BUY_FORM_ADD_TO_CART, () => { this.enableAddToCartButton(); this.buttonStateByListener = true; });
         document.addEventListener(RELOAD_NOTE_BUY_FORM, this.reloadBuyFormNote.bind(this) as EventListener);
      }

      const observer = new MutationObserver(() => {
         this.enableAddToCartButton();
         initializeTooltips();
      });
      observer.observe(this.element, { childList: true, subtree: true });
   }

   addToCartHover(e: MouseEvent) {
      const isValid = !this.hasVariationsValue || !!this.variationIdValue || (this.controlButtonByListenersValue && this.buttonStateByListener);
      if (!isValid) {
         if (e.type == 'mouseenter') {
            this.disableAddToCartButton();
         } else if (e.type == 'mouseleave' && !this.addToCartButtonTarget.classList.contains('clicked')) {
            this.enableAddToCartButton();
         }
      } else {
         this.enableAddToCartButton();
      }
   }

   addToCart(e: any) {
      const variationInputs = Array.from(this.element.querySelectorAll('input[name*="[id_variation]"]') as NodeListOf<HTMLInputElement>);
      const b2b = this.element.querySelector('[data-b2b-list]') as HTMLInputElement | null;

      const isValid = !this.hasVariationsValue || !!this.variationIdValue || (this.controlButtonByListenersValue && this.buttonStateByListener);

      if (isValid || (variationInputs.length && b2b)) {
         const productId = this.productIdValue;
         const variationId = this.variationIdValue;

         const pieces = this.getBuyCount();

         const clickAddToCart = this.addToCartButtonTarget?.getAttribute('data-tracking-clickaddtocart');
         const data = (typeof clickAddToCart === 'string')
            ? JSON.parse(clickAddToCart)
            : (clickAddToCart as object);

         if (this.hasAddToCartButtonTarget) {
            this.addToCartButtonTarget.classList.add('disabled');
            this.addToCartButtonTarget.insertAdjacentHTML('beforeend', '<div class="add-to-cart-loader"></div>');

            let gtmData = {'quantity': pieces ?? 1, 'ecommerce': { 'items' : {}}};
            let id = productId.toString();
            if (variationId) {
               id += '_' + variationId;
            }
            gtmData.ecommerce.items[0] = {item_id: '*' + id + ''};
            this.addToCartButtonTarget.setAttribute('data-gtm-placeholders', JSON.stringify(gtmData));
         }

         let productData: Record<string, any> = {
            productId: productId,
            variationId: variationId ? Number(variationId) : null as number,
            // parentElement, protoze se potřebujeme dostat na darky, který nemusí být součástí buyformu
            // pokud to bude zlobit, tak smazat a nechat this.element = buyform
            note: this.fetchProductNotes(this.element.parentElement ?? this.element),
         };

         const giftCardPrice = this.getGiftCardPrice();
         if (giftCardPrice) {
            productData.note = {
               ...productData.note,
               gift_card: giftCardPrice,
            };
         }

         const productSets = this.element.querySelectorAll('.set-submit-block input[name^=note]');
         if (variationInputs.length > 0 && !productSets.length) {
            productData = this.getMultipleInsertVariationsData(productId, variationInputs);
         }

         if (!Array.isArray(productData)) {
            if (data?.add?.products?.[0]) {
               const productJson = data.add.products[0];
               productData = {
                  ...productData,
                  name: productJson.name,
                  price: {
                     withVat: productJson.priceWithVat,
                     withoutVat: productJson.priceWithoutVat
                  }
               };
            }
         }

         const productAddedToCart = () => {
            this.addToCartButtonTarget.classList.add('btn-product-added');
            this.addToCartButtonTarget.classList.remove('disabled');

            this.addToCartButtonTarget.querySelector('.add-to-cart-loader').remove();

            setTimeout(() => this.addToCartButtonTarget.classList.remove('btn-product-added'), 600);
         };

         const options = {
            buttonElement: this.addToCartButtonTarget,
            additionalData: {
               title: data?.add?.products[0]?.name
            },
            blockingPromise: true
         };

         if (Array.isArray(productData)) {
            if (productData.length <= 0) {
               this.addToCartButtonTarget.classList.remove('disabled');
               this.addToCartButtonTarget.querySelector('.add-to-cart-loader').remove();

               return;
            }
            window.wpj.jsShop.addProductsToCart(productData as [], productData.map(val => Number(parseFloat(val.pieces))), options)
               .then(productAddedToCart);
         } else {
            window.wpj.jsShop.addProductToCart(productData as IAddedProduct, (!pieces || Number.isNaN(pieces)) ? 1 : +pieces, options)
               .then(productAddedToCart);
         }
      } else {
         if (wpj.jsShop && 'addToast' in wpj.jsShop) {
            wpj.jsShop.addToast(e.params.variationErrorMessage);
         }
         this.disableAddToCartButton();
         this.addToCartButtonTarget.classList.add('clicked');
         this.addToCartButtonTarget.setAttribute('data-gtm-placeholders', JSON.stringify({quantity: 'has-variation-error'}));
      }

      document.addEventListener('cartOpened', () => {
         try {
            // zavreni modalu pri nakupu z katalogu (pro jistotu v tryCatch block, nejspis ale neni potreba)
            if (this.component) {
               const modalCloseButton: HTMLElement = this.component.element
                  .closest('.wpj-modal-overlay')
                  ?.querySelector('[data-modal-close]');
               if (modalCloseButton) {
                  modalCloseButton?.click();
               }
            }
         } catch (e) {
            console.log(e);
         }
      })
   }

   private getBuyCount() {
      const input = this.element.querySelector('input[name="No"]') as HTMLInputElement | null;
      if (!(input instanceof HTMLInputElement)) {
         return null;
      }

      return input.valueAsNumber;
   }

   private getGiftCardPrice() {
      if (this.hasGiftCardPriceTarget) {
         const input = this.giftCardPriceTarget as HTMLInputElement;
         return {
            price: input.valueAsNumber,
            currency: input.getAttribute('data-currency')
         };
      }

      return null;
   }

   protected fetchProductNotes($buyForm: HTMLElement) {
      let note = {};
      [...$buyForm.querySelectorAll('[data-buy-form-note]')].forEach((element: any) => {
         if (element.type && element.type === 'checkbox' && !element.checked) {
            return;
         } else if (element?.dataset?.buyFormNote ?? false) {
            const parsedNote = JSON.parse(element?.dataset?.buyFormNote);
            let mainKey = Object.keys(parsedNote)[0];
            if (element.type === 'select-one') {
               note[mainKey] = {};
               note[mainKey][parsedNote[mainKey]] = element.value;
            } else {
               note[mainKey] = { ...note[mainKey], ...parsedNote[mainKey] };
            }
         }
      });
      return note;
   }

   protected getMultipleInsertVariationsData(idProduct: number, variations: HTMLInputElement[]) {
      const productData = [];
      variations.forEach(element => {
         const idVariation = element.value;
         const pieces = Number((document.querySelector(`[name="items[${idVariation}][pieces]"]`) as HTMLInputElement)?.value);

         if (!pieces) {
            return;
         }

         productData.push({
            productId: idProduct,
            variationId: Number(idVariation),
            pieces
         });
      });

      return productData;
   }

   enableAddToCartButton() {
      if (this.hasAddToCartButtonTarget) {
         this.addToCartButtonTarget.classList.remove('has-variation-error');
         this.addToCartButtonTarget.disabled = false;
      }
   }

   disableAddToCartButton() {
      if (this.hasAddToCartButtonTarget) {
         this.addToCartButtonTarget.classList.add('has-variation-error');
         this.addToCartButtonTarget.disabled = true;
      }
   }

   reloadBuyFormNote(event: CustomEvent) {
      if (this.component) {
         void this.component.set('note', event.detail, true);
      }
   }
}
