/**
 * Copyright since 2007 PrestaShop SA and Contributors
 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is bundled with this package in the file LICENSE.md.
 * It is also available through the world-wide-web at this URL:
 * https://opensource.org/licenses/OSL-3.0
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
 * versions in the future. If you wish to customize PrestaShop for your
 * needs please refer to https://devdocs.prestashop.com/ for more information.
 *
 * @author    PrestaShop SA and Contributors <contact@prestashop.com>
 * @copyright Since 2007 PrestaShop SA and Contributors
 * @license   https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
 */

$(document).ready(() => {
  window.form.init();
  nav.init();
  featuresCollection.init();
  displayFormCategory.init();
  formCategory.init();
  stock.init();
  supplier.init();
  warehouseCombinations.init();
  customFieldCollection.init();
  virtualProduct.init();
  attachmentProduct.init();
  imagesProduct.init();
  priceCalculation.init();
  displayFieldsManager.refresh();
  displayFieldsManager.init(virtualProduct);
  seo.init();
  tags.init();
  rightSidebar.init();
  recommendedModules.init();
  BOEvent.emitEvent('Product Categories Management started', 'CustomEvent');
  BOEvent.emitEvent('Product Default category Management started', 'CustomEvent');
  BOEvent.emitEvent('Product Manufacturer Management started', 'CustomEvent');
  BOEvent.emitEvent('Product Related Management started', 'CustomEvent');
  BOEvent.emitEvent('Modal confirmation started', 'CustomEvent');
  BOEvent.emitEvent('Product Combinations Management started', 'CustomEvent');

  /** Type product fields display management */
  $('#form_step1_type_product').change(() => {
    displayFieldsManager.refresh();
  });

  // Validate price fields on input change
  $(".money-type input[type='text']").change(function validate() {
    const inputValue = priceCalculation.normalizePrice($(this).val());
    const parsedValue = truncateDecimals(inputValue, 6);

    $(this).val(parsedValue);
  });

  /** tooltips should be hidden when we move to another tab */
  $('#form-nav').on('click', '.nav-item', () => {
    $('[data-toggle="tooltip"]').tooltip('hide');
    $('[data-toggle="popover"]').popover('hide');
    resetEditor();
  });

  $('.summary-description-container a[data-toggle="tab"]').on('shown.bs.tab', resetEditor);
  form.switchLanguage($('#form_switch_language').val());
});

/**
 * Reset active tinyMce editor (triggered when switch language, or switching tabs)
 */
function resetEditor() {
  if (!window.tinyMCE) {
    return;
  }

  const languageEditorsSelector = '.summary-description-container div.translation-field.active textarea.autoload_rte';
  $(languageEditorsSelector).each((index, textarea) => {
    const editor = window.tinyMCE.get(textarea.id);

    if (!editor) {
      return;
    }

    // Reset content to force refresh of editor
    editor.setContent(editor.getContent());
    setTimeout(() => {
      editor.execCommand('mceInsertContent', false, '', {skip_focus: true});
      editor.execCommand('mceAutoResize');
    }, 250);
  });
}

/**
 * Manage show or hide fields
 */
window.displayFieldsManager = (function () {
  const typeProduct = $('#form_step1_type_product');
  const showVariationsSelector = $('#show_variations_selector');
  const combinationsBlock = $('#combinations');
  let managedVirtualProduct;

  return {
    init(virtualProduct) {
      managedVirtualProduct = virtualProduct;

      /** Type product fields display management */
      $('#form_step1_type_product').change(() => {
        displayFieldsManager.refresh();
      });

      $('#form .form-input-title input').on('focus', function () {
        $(this).select();
      });

      this.initVisibilityRule();

      /** Tax rule dropdown shortcut */
      $('a#tax_rule_shortcut_opener').on('click', () => {
        // lazy instantiated
        let duplicate = $('#form_step2_id_tax_rules_group_shortcut');

        if (duplicate.length === 0) {
          const origin = $('select#form_step2_id_tax_rules_group');
          duplicate = origin.clone(false).attr('id', 'form_step2_id_tax_rules_group_shortcut');
          origin.on('change', () => {
            duplicate.val(origin.val()); // no change() here to avoid infinite loop.
          });
          duplicate.on('change', () => {
            origin.val(duplicate.val()).change();
          });
          duplicate.appendTo($('#tax_rule_shortcut'));
        }
        duplicate.parent().parent().show();

        return false;
      });
    },
    /**
     * When a product is available for order, its price should be visible,
     * whereas products unavailable for order can have their prices visible or hidden.
     */
    initVisibilityRule() {
      const showPriceSelector = '.js-show-price';
      const availableForOrderSelector = '.js-available-for-order';

      const applyVisibilityRule = function applyVisibilityRule() {
        const $availableForOrder = $(`${availableForOrderSelector} input`);
        const $showPrice = $(`${showPriceSelector} input`);
        const $showPriceColumn = $(showPriceSelector);

        if ($availableForOrder.prop('checked')) {
          $showPrice.prop('checked', true);
          $showPriceColumn.addClass('hide');
        } else {
          $showPriceColumn.removeClass('hide');
        }
      };
      $(`${availableForOrderSelector} .checkbox`).on('click', applyVisibilityRule);
      applyVisibilityRule();
    },
    refresh() {
      this.checkAccessVariations();
      $('#virtual_product').hide();
      $('#form-nav a[href="#step3"]').text(translate_javascripts.Quantities);

      /** product type switch */

      if (typeProduct.val() === '1') {
        $('#pack_stock_type, #js_form_step1_inputPackItems').show();
        $('#form-nav a[href="#step4"]').show();
        showVariationsSelector.hide();
        showVariationsSelector.find('input[value="0"]').attr('checked', true);
      } else {
        $('#virtual_product, #pack_stock_type, #js_form_step1_inputPackItems').hide();
        $('#form-nav a[href="#step4"]').show();

        if (typeProduct.val() === '2') {
          showVariationsSelector.hide();
          $('#virtual_product').show();
          $('#form-nav a[href="#step4"]').hide();
          showVariationsSelector.find('input[value="0"]').attr('checked', true);
          $('#form-nav a[href="#step3"]').text(translate_javascripts['Virtual product']);
        } else {
          showVariationsSelector.show();
          $('#form-nav a[href="#step3"]').text(translate_javascripts.Quantities);
        }
      }

      // Switching from a product type to another which is not "Virtual product",
      // triggers the destruction of pre-existing virtual product
      const shouldDestroyVirtualProduct = typeProduct.val() !== '2';

      if (shouldDestroyVirtualProduct && managedVirtualProduct !== undefined) {
        managedVirtualProduct.destroy();
      }

      /** check quantity / combinations display */
      if (
        showVariationsSelector.find('input:checked').val() === '1'
        || $('#accordion_combinations tr:not(#loading-attribute)').length > 0
      ) {
        combinationsBlock.show();

        $('#form-nav a[href="#step3"]').text(translate_javascripts.Combinations);
        $('#product_qty_0_shortcut_div, #quantities').hide();
      } else {
        combinationsBlock.hide();
        $('#product_qty_0_shortcut_div, #quantities').show();
      }

      /** Tooltip for product type combinations */
      if ($('input[name="show_variations"][value="1"]:checked').length >= 1) {
        $('#product_type_combinations_shortcut').show();
      } else {
        $('#product_type_combinations_shortcut').hide();
      }
    },
    getProductType() {
      /* eslint-disable */
      switch (typeProduct.val()) {
        case '0':
          return 'standard';
          break;
        case '1':
          return 'pack';
          break;
        case '2':
          return 'virtual';
          break;
        default:
          return 'standard';
      }
      /* eslint-enable */
    },
    /**
     * Product pack or virtual can't have variations
     * Warn e-merchant.
     * @param errorMessage
     */
    checkAccessVariations() {
      if (
        (showVariationsSelector.find('input:checked').val() === '1'
        || $('#accordion_combinations tr:not(#loading-attribute)').length > 0)
        && (typeProduct.val() === '1'
        || typeProduct.val() === '2')
      ) {
        const typeOfProduct = this.getProductType();
        // eslint-disable-next-line
        const errorMessage = `You can't create ${typeOfProduct} product with variations. Are you sure to disable variations ? they will all be deleted.`;
        modalConfirmation.create(translate_javascripts[errorMessage], null, {
          onCancel() {
            typeProduct.val(0).change();
            /* else the radio bouton is not display even if checked attribute is true */
            $('#show_variations_selector input[value="1"]').click();
          },
          onContinue() {
            $.ajax({
              type: 'GET',
              // eslint-disable-next-line
              url: $('#accordion_combinations').attr('data-action-delete-all').replace(/delete-all\/\d+/, `delete-all/${$('#form_id_product').val()}`),
              success() {
                $('#accordion_combinations .combination').remove();
                displayFieldsManager.refresh();
              },
              error(response) {
                showErrorMessage(jQuery.parseJSON(response.responseText).message);
              },
            });
          },
        }).show();
      }
    },
  };
}());

/**
 * Display category form management
 */
const displayFormCategory = (function () {
  const parentElem = $('#add-categories');

  return {
    init() {
      /** Click event on the add button */
      parentElem.find('a.open').on('click', function (e) {
        e.preventDefault();
        parentElem.find('#add-categories-content').removeClass('hide');
        $(this).hide();
      });
    },
  };
}());

/**
 * Form category management
 */
const formCategory = (function () {
  const elem = $('#form_step1_new_category');

  /** Send category form and it to nested categories */
  function send(form) {
    $.ajax({
      type: 'POST',
      url: elem.attr('data-action'),
      data: {
        'form[category][name]': $('#form_step1_new_category_name').val(),
        'form[category][id_parent]': $('#form_step1_new_category_id_parent').val(),
        'form[_token]': $('#form #form__token').val(),
      },
      beforeSend() {
        $('button.submit', elem).attr('disabled', 'disabled');
        $('ul.text-danger', elem).remove();
        $('*.has-danger', elem).removeClass('has-danger');
        $('*.has-danger').removeClass('has-danger');
      },
      success(response) {
        // inject new category into category tree
        let html = `<li>
          <div class="checkbox js-checkbox">
            <label>
              <input type="checkbox" name="form[step1][categories][tree][]" checked value="${response.category.id}">
              ${response.category.name[1]}
              <input type="radio" value="${response.category.id}" name="ignore" class="default-category">
            </label>
          </div>
          </li>`;

        const parentElement = $(`#form_step1_categories input[value=${response.category.id_parent}]`).parent().parent();

        if (parentElement.next('ul').length === 0) {
          html = `<ul>${html}</ul>`;
          parentElement.append(html);
        } else {
          parentElement.next('ul').append(html);
        }

        // inject new category in parent category selector
        // eslint-disable-next-line
        $('#form_step1_new_category_id_parent').append(`<option value="${response.category.id}">${response.category.name[1]}</option>`);

        // create label
        const tag = {
          name: response.category.name[1],
          id: response.category.id,
          breadcrumb: '',
        };
        productCategoriesTags.createTag(tag);

        // hide the form
        form.hideBlock();
      },
      error(response) {
        $.each(jQuery.parseJSON(response.responseText), (key, errors) => {
          let html = '<ul class="list-unstyled text-danger">';
          $.each(errors, (errorsKey, error) => {
            html += `<li>${error}</li>`;
          });
          html += '</ul>';

          $(`#form_step1_new_${key}`).parent().append(html);
          $(`#form_step1_new_${key}`).parent().addClass('has-danger');
        });
      },
      complete() {
        $('#form_step1_new_category button.submit').removeAttr('disabled');
      },
    });
  }

  return {
    init() {
      const that = this;
      /** remove all categories from selector, except pre defined */
      $('#add-categories button.save').click(() => {
        send(that);
      });
      $('#add-categories button[type="reset"]').click(() => {
        that.hideBlock();
      });
    },
    hideBlock() {
      $('#form_step1_new_category_name').val('');
      $('#add-category-button').show();
      $('#add-categories-content').addClass('hide');
    },
  };
}());

/**
 * Feature collection management
 */
const featuresCollection = (function () {
  const collectionHolder = $('.feature-collection');
  let maxCollectionChildren = collectionHolder.children('.row').length;

  /** Add a feature */
  function add() {
    const newForm = collectionHolder.attr('data-prototype').replace(/__name__/g, maxCollectionChildren);
    collectionHolder.append(newForm);
    maxCollectionChildren += 1;
    prestaShopUiKit.initSelects();
  }

  return {
    init() {
      /** Click event on the add button */
      $('#features .add').on('click', (e) => {
        e.preventDefault();
        add();
        $('#features-content').removeClass('hide');
      });

      /** Click event on the remove button */
      $(document).on('click', '.feature-collection .delete', function (e) {
        e.preventDefault();
        const that = $(this);

        modalConfirmation.create(translate_javascripts['Are you sure you want to delete this item?'], null, {
          onContinue() {
            that.closest('.product-feature').remove();
          },
        }).show();
      });

      function replaceEndingIdFromUrl(url, newId) {
        return url.replace(/\/\d+(?!.*\/\d+)((?=\?.*))?/, `/${newId}`);
      }

      /** On feature selector event change, refresh possible values list */
      $(document).on('change', '.feature-collection select.feature-selector', function (event) {
        const that = event.currentTarget;
        const $row = $($(that).parents('.row')[0]);
        const $selector = $row.find('.feature-value-selector');

        if ($(this).val() !== '') {
          $.ajax({
            url: replaceEndingIdFromUrl($(this).attr('data-action'), $(this).val()),
            success(response) {
              $selector.prop('disabled', response.length === 0);
              $selector.empty();
              $.each(response, (index, elt) => {
                // the placeholder shouldn't be posted.
                if (elt.id === '0') {
                  elt.id = '';
                }
                $selector.append($('<option></option>').attr('value', elt.id).text(elt.value));
              });
            },
          });
        }
      });

      const $featuresContainer = $('#features-content');

      $featuresContainer.on('change', '.row select, .row input[type="text"]', (event) => {
        const that = event.currentTarget;
        const $row = $($(that).parents('.row')[0]);
        const $definedValueSelector = $row.find('.feature-value-selector');
        const $customValueSelector = $row.find('input[type=text]');

        // if feature has changed we need to reset values
        if ($(that).hasClass('feature-selector')) {
          $customValueSelector.val('');
          $definedValueSelector.val('');
        }
      });
    },
  };
}());

/**
 * Suppliers management
 */
const supplier = (function () {
  const supplierInputManage = function (input) {
    // eslint-disable-next-line
    const supplierDefaultInput = $(`#form_step6_suppliers input[name="form[step6][default_supplier]"][value=${$(input).val()}]`);

    if ($(input).is(':checked')) {
      supplierDefaultInput.prop('disabled', false).show();
    } else {
      supplierDefaultInput.prop('disabled', true).hide();
    }
  };

  return {
    init() {
      /** On supplier select, hide or show the default supplier selector */
      const supplierInput = $('#form_step6_suppliers input[name="form[step6][suppliers][]"]');
      supplierInput.change(function () {
        supplierInputManage($(this));
        supplierCombinations.refresh();
      });

      // default display
      $('#form_step6_suppliers input[name="form[step6][suppliers][]"]').each(function () {
        supplierInputManage($(this));
      });
    },
  };
}());

/**
 * Supplier combination collection management
 */
window.supplierCombinations = (function () {
  const idProduct = $('#form_id_product').val();
  const collectionHolder = $('#supplier_combination_collection');

  return {
    refresh() {
      const suppliers = $('#form_step6_suppliers input[name="form[step6][suppliers][]"]:checked').map(function () {
        return $(this).val();
      }).get();
      const url = collectionHolder.attr('data-url')
        .replace(
          /refresh-product-supplier-combination-form\/\d+\/\d+/,
          // eslint-disable-next-line
          `refresh-product-supplier-combination-form/${idProduct}${suppliers.length > 0 ? `/${suppliers.join('-')}` : ''}`,
        );
      $.ajax({
        url,
        success(response) {
          collectionHolder.empty().append(response);
        },
      });
    },
  };
}());

/**
 * Quantities management
 */
window.stock = (function () {
  return {
    init() {
      /** Update qty_0 and shortcut qty_0 field on change */
      $('#form_step1_qty_0_shortcut, #form_step3_qty_0').on('change', function () {
        if ($(this).attr('id') === 'form_step1_qty_0_shortcut') {
          $('#form_step3_qty_0').val($(this).val());
        } else {
          $('#form_step1_qty_0_shortcut').val($(this).val());
        }
      });

      /** if GSA : Show depends_on_stock choice only if advanced_stock_management checked */
      $('#form_step3_advanced_stock_management').on('change', (e) => {
        if (e.target.checked) {
          $('#depends_on_stock_div').show();
        } else {
          $('#depends_on_stock_div').hide();
        }
        warehouseCombinations.refresh();
      });

      /** if GSA activation change on 'depend on stock', update quantities fields */
      // eslint-disable-next-line
      $('#form_step3_depends_on_stock_0, #form_step3_depends_on_stock_1, #form_step3_advanced_stock_management').on('change', (e) => {
        displayFieldsManager.refresh();
        warehouseCombinations.refresh();
      });
      displayFieldsManager.refresh();
    },
  };
}());

/**
 * Navigation management
 */
window.nav = (function () {
  return {
    init() {
      /** Manage tabls hash routes */
      const {hash} = document.location;
      const formNav = $('#form-nav');
      const prefix = 'tab-';

      if (hash) {
        formNav.find(`a[href='${hash.replace(prefix, '')}']`).tab('show');
      }

      formNav.find('a').on('shown.bs.tab', (e) => {
        if (e.target.hash) {
          window.location.hash = e.target.hash.replace('#', `#${prefix}`);
        }
      });
    },
  };
}());

/**
 * Warehouse combination collection management (ASM only)
 */
window.warehouseCombinations = (function () {
  const idProduct = $('#form_id_product').val();
  const collectionHolder = $('#warehouse_combination_collection');

  return {
    init() {
      // toggle all button action
      $(document).on('click', 'div[id^="warehouse_combination_"] button.check_all_warehouse', function () {
        const checkboxes = $(this).closest('div[id^="warehouse_combination_"]')
          .find('input[type="checkbox"][id$="_activated"]');
        checkboxes.prop('checked', checkboxes.filter(':checked').length === 0);
      });
      // location disablation depending on 'stored' checkbox
      // eslint-disable-next-line
      $(document).on('change', 'div[id^="warehouse_combination_"] input[id^="form_step4_warehouse_combination_"][id$="_activated"]', function () {
        const checked = $(this).prop('checked');
        const location = $(this).closest('div.form-group')
          .find('input[id^="form_step4_warehouse_combination_"][id$="_location"]');
        location.prop('disabled', !checked);
        if (!checked) {
          location.val('');
        }
      });
      this.locationDisabler();
    },
    locationDisabler() {
      // eslint-disable-next-line
      $('div[id^="warehouse_combination_"] input[id^="form_step4_warehouse_combination_"][id$="_activated"]', collectionHolder).each(function () {
        const checked = $(this).prop('checked');
        const location = $(this).closest('div.form-group')
          .find('input[id^="form_step4_warehouse_combination_"][id$="_location"]');
        location.prop('disabled', !checked);
      });
    },
    refresh() {
      const show = $('input#form_step3_advanced_stock_management:checked').length > 0;

      if (show) {
        const url = collectionHolder.attr('data-url').replace(/\/\d+(?=\?.*)/, `/${idProduct}`);
        $.ajax({
          url,
          success(response) {
            collectionHolder.empty().append(response);
            collectionHolder.show();
            warehouseCombinations.locationDisabler();
          },
        });
      } else {
        collectionHolder.hide();
      }
    },
  };
}());

/**
 * Form management
 */
window.form = (function () {
  const elem = $('#form');

  function send(redirect, target, callBack) {
    // target value by default
    if (typeof (target) === 'undefined') {
      // eslint-disable-next-line
      target = false;
    }
    seo.onSave();
    updateMissingTranslatedNames();

    const data = $('input, textarea, select', elem)
      .not(':input[type=button], :input[type=submit], :input[type=reset]')
      .serialize();
    let openBlank;

    if (target === '_blank' && redirect) {
      openBlank = window.open('about:blank', target, '');
      openBlank.document.write(
        `<p style="text-align: center;">
          <img src="${document.location.origin}${baseAdminDir}/themes/default/img/spinner.gif">
         </p>`,
      );
    }

    $.ajax({
      type: 'POST',
      data,
      beforeSend() {
        $('#submit', elem).attr('disabled', 'disabled');
        $('.btn-submit', elem).attr('disabled', 'disabled');
        $('ul.text-danger').remove();
        $('*.has-danger').removeClass('has-danger');
        $('#form-nav li.has-error').removeClass('has-error');
        updateDisplayGlobalErrors(null);
      },
      success(response) {
        if (callBack) {
          callBack();
        }
        showSuccessMessage(translate_javascripts['Form update success']);
        // update the customization ids
        if (typeof response.customization_fields_ids !== 'undefined') {
          $.each(response.customization_fields_ids, (k, v) => {
            $(`#form_step6_custom_fields_${k}_id_customization_field`).val(v);
          });
        }

        $('.js-spinner').hide();

        if (!redirect) {
          return;
        }

        if (target === false) {
          window.location = redirect;

          return;
        }

        if (target !== '_blank') {
          window.open(redirect, target);

          return;
        }

        openBlank.location = redirect;
      },
      error(response) {
        showErrorMessage(translate_javascripts['Form update errors']);

        if (target === '_blank' && redirect) {
          openBlank.close();
        }

        const tabsWithErrors = [];

        $.each(jQuery.parseJSON(response.responseText), (key, errors) => {
          tabsWithErrors.push(key);

          let html = '<ul class="list-unstyled text-danger">';
          $.each(errors, (unusedKey, error) => {
            html += `<li>${error}</li>`;
          });
          html += '</ul>';

          if (key.localeCompare('error') === 0) {
            updateDisplayGlobalErrors(html);
          } else if (key.match(/^combination_.*/)) {
            $(`#${key}`).parent().addClass('has-danger').append(html);
          } else {
            $(`#form_${key}`).parent().addClass('has-danger').append(html);
          }
        });

        /** find first tab with error, then switch to it */
        tabsWithErrors.sort();
        $.each(tabsWithErrors, (key, tabIndex) => {
          if (key === 0) {
            $(`#form-nav li a[href="#${tabIndex.split('_')[0]}"]`).tab('show');
          }

          $(`#form-nav li a[href="#${tabIndex.split('_')[0]}"]`).parent().addClass('has-error');
        });

        if ($('div[class*="translation-label-"].has-danger').length > 0) {
          const regexLabel = 'translation-label-';

          const translationLabelClass = $.grep(
            $('div[class*="translation-label-"].has-danger')
              .first()
              .attr('class')
              .split(' '),
            (v) => v.indexOf(regexLabel) === 0,
          )
            .join();

          if (translationLabelClass) {
            const selectValue = translationLabelClass.replace(regexLabel, '');

            if ($(`#form_switch_language option[value="${selectValue}"]`).length > 0) {
              $('#form_switch_language').val(selectValue).change();
            }
          }
        }

        /** scroll to 1st error */
        if ($('.has-danger').first().offset()) {
          $('html, body').animate({
            scrollTop: $('.has-danger').first().offset().top - $('nav.main-header').height(),
          }, 500);
        }
      },
      complete() {
        $('#submit', elem).removeAttr('disabled');
        $('.btn-submit', elem).removeAttr('disabled');
      },
    });
  }

  function switchLanguage(isoCode) {
    $(`div.translations.tabbable > div > div.translation-field:not(.translation-label-${isoCode})`)
      .removeClass('show active');

    $(`div.translations.tabbable > div > div.translation-field.translation-label-${isoCode}`).addClass('show active');
    resetEditor();
  }

  function updateMissingTranslatedNames() {
    const namesDiv = $('#form_step1_names');
    let defaultLanguageValue = null;
    $("input[id^='form_step1_name_']", namesDiv).each(function (index) {
      const value = $(this).val();

      // The first language is ALWAYS the employee language
      if (index === 0) {
        defaultLanguageValue = value;
      } else if (value.length === 0) {
        $(this).val(defaultLanguageValue);
      }
    });
  }

  /**
   * Depending on the provided params, this method displays or hides
   * an error panel with the form errors not linked to a specific field.
   *
   * @param {string} content The HTML content to display
   */
  function updateDisplayGlobalErrors(content) {
    const target = $('#form_bubbling_errors');
    target.html('');
    if (content) {
      target.html(`<div class="alert alert-danger">${content}</div>`);
    }
  }
  return {
    init() {
      /** prevent form submit on ENTER keypress */
      jwerty.key('enter', (e) => {
        e.preventDefault();
      });

      /** create keyboard event for save */
      jwerty.key('alt+shift+S', (e) => {
        e.preventDefault();
        send();
      });

      /** create keyboard event for save & duplicate */
      jwerty.key('alt+shift+D', (e) => {
        e.preventDefault();
        send($('.product-footer .duplicate').attr('data-redirect'));
      });

      /** create keyboard event for save & new */
      jwerty.key('alt+shift+P', (e) => {
        e.preventDefault();
        send($('.product-footer .new-product').attr('data-redirect'));
      });

      /** create keyboard event for save & go catalog */
      jwerty.key('alt+shift+Q', (e) => {
        e.preventDefault();
        send($('.product-footer .go-catalog').attr('data-redirect'));
      });

      /** create keyboard event for save & go preview */
      jwerty.key('alt+shift+V', (e) => {
        e.preventDefault();
        const productFooter = $('.product-footer .preview');
        send(productFooter.attr('data-redirect'), productFooter.attr('target'));
      });

      /** create keyboard event for save & active or desactive product */
      jwerty.key('alt+shift+O', (e) => {
        e.preventDefault();
        const step1CheckBox = $('#form_step1_active');
        step1CheckBox.prop('checked', !step1CheckBox.is(':checked'));
      });

      elem.submit((event) => {
        replaceBadLocaleCharacters();
        event.preventDefault();
        send();
      });

      elem.find('#form_switch_language').change((event) => {
        event.preventDefault();
        switchLanguage(event.target.value);
      });

      /** on save with duplicate|new|preview */
      $('.btn-submit, .preview', elem).click(function (event) {
        event.preventDefault();
        send($(this).attr('data-redirect'), $(this).attr('target'));
      });

      $('.js-btn-save').on('click', function (event) {
        replaceBadLocaleCharacters();
        event.preventDefault();
        $('.js-spinner').css('display', 'inline-block');
        send($(this).attr('href'));
      });

      /** on active field change, send form */
      $('#form_step1_active', elem).on('change', function () {
        const active = $(this).prop('checked');
        $('.for-switch.online-title').toggle(active);
        $('.for-switch.offline-title').toggle(!active);
        // update link preview
        const previewButton = $('#product_form_preview_btn');
        const urlActive = previewButton.attr('data-redirect');
        const urlDeactive = previewButton.attr('data-url-deactive');
        previewButton.attr('data-redirect', urlDeactive);
        previewButton.attr('data-url-deactive', urlActive);
        // update product
        send();
      });

      /** on delete product */
      $('.product-footer .delete', elem).click(function (e) {
        e.preventDefault();
        const that = $(this);
        modalConfirmation.create(translate_javascripts['Are you sure you want to delete this item?'], null, {
          onContinue() {
            window.location = that.attr('href');
          },
        }).show();
      });

      $('#form-loading').fadeIn(() => {
      /** Create Bloodhound engine */
        const engine = new Bloodhound({
          datumTokenizer(d) {
            return Bloodhound.tokenizers.whitespace(d.label);
          },
          queryTokenizer: Bloodhound.tokenizers.whitespace,
          prefetch: {
            url: $('#form_step3_attributes').attr('data-prefetch'),
            cache: false,
          },
        });

        /** init input typeahead */
        $('#form_step3_attributes').tokenfield({
          typeahead: [{
            hint: false,
            cache: false,
          }, {
            source(query, syncResults) {
              engine.search(query, (suggestions) => {
                syncResults(filter(suggestions));
              });
            },
            display: 'label',
          }],
          minWidth: '768px',
        });

        /** Filter suggestion with selected tokens */
        const filter = function (suggestions) {
          const selected = [];
          $('#attributes-generator input.attribute-generator').each(function () {
            selected.push($(this).val());
          });

          // eslint-disable-next-line
          return $.grep(suggestions, (suggestion) => $.inArray(suggestion.value, selected) === -1 && $.inArray(`group-${suggestion.data.id_group}`, selected) === -1);
        };

        /** On event "tokenfield:createtoken" : check values are valid if its not a typehead result */
        // eslint-disable-next-line
        $('#form_step3_attributes').on('tokenfield:createtoken', (e) => {
          if (!e.attrs.data) {
            if (e.handleObj.origType !== 'tokenfield:createtoken') {
              return false;
            }

            const orgLabel = e.attrs.label;

            if (e.attrs.label === e.attrs.value) {
              engine.search(e.attrs.label, (result) => {
                if (result.length >= 1) {
                  e.attrs.label = result[0].label;
                  e.attrs.value = result[0].value;
                  e.attrs.data = [];
                  e.attrs.data.id_group = result[0].data.id_group;
                }
              });
            } else {
              const attr = $(`.js-attribute-checkbox[data-value="${e.attrs.value}"]`);

              if (attr) {
                e.attrs.label = attr.data('label');
                e.attrs.value = attr.data('value');
                e.attrs.data = [];
                e.attrs.data.id_group = attr.data('group-id');
              }
            }

            if (e.attrs.data && filter([e.attrs]).length === 0) {
              $('#form_step3_attributes-tokenfield').val((i, value) => value.replace(orgLabel, ''));
              return false;
            }
          }
        });

        /** On event "tokenfield:createdtoken" : store attributes in input when add a token */
        $('#form_step3_attributes').on('tokenfield:createdtoken', (e) => {
          if (e.attrs.data) {
            // eslint-disable-next-line
            $('#attributes-generator').append(`<input type="hidden" id="attribute-generator-${e.attrs.value}" class="attribute-generator" value="${e.attrs.value}" name="options[${e.attrs.data.id_group}][${e.attrs.value}]" />`);
          } else {
            $(e.relatedTarget).addClass('invalid');
          }
        });

        /** On event "tokenfield:removedtoken" : remove stored attributes input when remove token */
        $('#form_step3_attributes').on('tokenfield:removedtoken', (e) => {
          if (!$(e.relatedTarget).hasClass('invalid')) {
            $(`#attribute-generator-${e.attrs.value}`).remove();
          }
        });
      });
    },
    send(redirect, target, callBack) {
      send(redirect, target, callBack);
    },
    switchLanguage(isoCode) {
      switchLanguage(isoCode);
    },
  };
}());

/**
 * Custom field collection management
 */
window.customFieldCollection = (function () {
  const collectionHolder = $('ul.customFieldCollection');
  let maxCollectionChildren = collectionHolder.children().length;

  /** Add a custom field */
  function add() {
    const newForm = collectionHolder.attr('data-prototype').replace(/__name__/g, maxCollectionChildren);
    maxCollectionChildren += 1;

    collectionHolder.append(`<li>${newForm}</li>`);
    window.prestaShopUiKit.init();
  }

  return {
    init() {
      /** Click event on the add button */
      $('#custom_fields a.add').on('click', (e) => {
        e.preventDefault();
        add();
      });

      /** Click event on the remove button */
      $(document).on('click', 'ul.customFieldCollection .delete', function (e) {
        e.preventDefault();
        const that = $(this);

        modalConfirmation.create(translate_javascripts['Are you sure you want to delete this item?'], null, {
          onContinue() {
            that.parent().parent().parent().remove();
          },
        }).show();
      });
    },
  };
}());

/**
 * virtual product management
 */
window.virtualProduct = (function () {
  const idProduct = $('#form_id_product').val();

  const getOnDeleteVirtualProductFileHandler = function ($deleteButton) {
    return $.ajax({
      type: 'GET',
      url: $deleteButton.attr('href').replace(/\/\d+(?=\?.*)/, `/${idProduct}`),
      success() {
        $('#form_step3_virtual_product_file_input').removeClass('hide').addClass('show');
        $('#form_step3_virtual_product_file_details').removeClass('show').addClass('hide');
      },
    });
  };

  return {
    init() {
      $(document).on('change', 'input[name="form[step3][virtual_product][is_virtual_file]"]', function () {
        if ($(this).val() === '1') {
          $('#virtual_product_content').show();
        } else {
          $('#virtual_product_content').hide();

          const url = $('#virtual_product').attr('data-action-remove').replace(/remove\/\d+/, `remove/${idProduct}`);
          // delete virtual product
          $.ajax({
            type: 'GET',
            url,
            success() {
              // empty form
              $('#form_step3_virtual_product_file_input').removeClass('hide').addClass('show');
              $('#form_step3_virtual_product_file_details').removeClass('show').addClass('hide');
              $('#form_step3_virtual_product_name').val('');
              $('#form_step3_virtual_product_nb_downloadable').val(0);
              $('#form_step3_virtual_product_expiration_date').val('');
              $('#form_step3_virtual_product_nb_days').val(0);
            },
          });
        }
      });

      $('#form_step3_virtual_product_file').change(function () {
        if ($(this)[0].files !== undefined) {
          const {files} = $(this)[0];
          let name = '';

          $.each(files, (index, value) => {
            name += `${value.name}, `;
          });
          $('#form_step3_virtual_product_name').val(name.slice(0, -2));
        } else {
          // Internet Explorer 9 Compatibility
          const name = $(this).val().split(/[\\/]/);
          $('#form_step3_virtual_product_name').val(name[name.length - 1]);
        }
      });

      if ($('input[name="form[step3][virtual_product][is_virtual_file]"]:checked').val() === '1') {
        $('#virtual_product_content').show();
      } else {
        $('#virtual_product_content').hide();
      }

      /** delete attached file */
      $('#form_step3_virtual_product_file_details .delete').click(function (e) {
        e.preventDefault();
        const $deleteButton = $(this);

        modalConfirmation.create(translate_javascripts['Are you sure you want to delete this item?'], null, {
          onContinue() {
            getOnDeleteVirtualProductFileHandler($deleteButton);
          },
        }).show();
      });

      /** save virtual product */
      $('#form_step3_virtual_product_save').click(function () {
        const that = $(this);
        const data = new FormData();

        if ($('#form_step3_virtual_product_file')[0].files[0]) {
          data.append('product_virtual[file]', $('#form_step3_virtual_product_file')[0].files[0]);
        }
        data.append('product_virtual[is_virtual_file]',
          $('input[name="form[step3][virtual_product][is_virtual_file]"]:checked').val(),
        );
        data.append('product_virtual[name]', $('#form_step3_virtual_product_name').val());
        data.append('product_virtual[nb_downloadable]', $('#form_step3_virtual_product_nb_downloadable').val());
        data.append('product_virtual[expiration_date]', $('#form_step3_virtual_product_expiration_date').val());
        data.append('product_virtual[nb_days]', $('#form_step3_virtual_product_nb_days').val());

        $.ajax({
          type: 'POST',
          url: $('#virtual_product').attr('data-action').replace(/save\/\d+/, `save/${idProduct}`),
          data,
          contentType: false,
          processData: false,
          beforeSend() {
            that.prop('disabled', 'disabled');
            $('ul.text-danger').remove();
            $('*.has-danger').removeClass('has-danger');
          },
          success(response) {
            showSuccessMessage(translate_javascripts['Form update success']);
            if (response.file_download_link) {
              $('#form_step3_virtual_product_file_details a.download').attr('href', response.file_download_link);
              $('#form_step3_virtual_product_file_input').removeClass('show').addClass('hide');
              $('#form_step3_virtual_product_file_details').removeClass('hide').addClass('show');
            }
          },
          error(response) {
            $.each(jQuery.parseJSON(response.responseText), (key, errors) => {
              let html = '<ul class="list-unstyled text-danger">';
              $.each(errors, (errorsKey, error) => {
                html += `<li>${error}</li>`;
              });
              html += '</ul>';

              $(`#form_step3_virtual_product_${key}`).parent().append(html);
              $(`#form_step3_virtual_product_${key}`).parent().addClass('has-danger');
            });
          },
          complete() {
            that.removeAttr('disabled');
          },
        });
      });
    },
    destroy() {
      const fileDetailsSelector = '#form_step3_virtual_product_file_details';
      const fileAssociationExists = !$(fileDetailsSelector).hasClass('hide');

      if (fileAssociationExists) {
        const $deleteButton = $(`${fileDetailsSelector} .delete`);
        getOnDeleteVirtualProductFileHandler($deleteButton);
      }

      const associatedFileCheckboxSelectorPrefix = '#form_step3_virtual_product_is_virtual_file_';
      $(`${associatedFileCheckboxSelectorPrefix}0`).prop('checked', false);
      $(`${associatedFileCheckboxSelectorPrefix}1`).prop('checked', true);

      $('#virtual_product_content input').val('');
    },
  };
}());

/**
 * attachment product management
 */
window.attachmentProduct = (function () {
  const idProduct = $('#form_id_product').val();

  return {
    init() {
      const buttonSave = $('#form_step6_attachment_product_add');
      const buttonCancel = $('#form_step6_attachment_product_cancel');

      buttonCancel.click(() => {
        resetAttachmentForm();
      });

      function resetAttachmentForm() {
        $('#form_step6_attachment_product_file').val('');
        $('#form_step6_attachment_product_name').val('');
        $('#form_step6_attachment_product_description').val('');
      }

      function replaceEndingIdFromUrl(url, newId) {
        return url.replace(/\/\d+(?!.*\/\d+)((?=\?.*))?/, `/${newId}`);
      }

      /** add attachment */
      // eslint-disable-next-line
      $('#form_step6_attachment_product_add').click(function () {
        const data = new FormData();

        if ($('#form_step6_attachment_product_file')[0].files[0]) {
          data.append('product_attachment[file]', $('#form_step6_attachment_product_file')[0].files[0]);
        }
        data.append('product_attachment[name]', $('#form_step6_attachment_product_name').val());
        data.append('product_attachment[description]', $('#form_step6_attachment_product_description').val());

        $.ajax({
          type: 'POST',
          url: replaceEndingIdFromUrl($('#form_step6_attachment_product').attr('data-action'), idProduct),
          data,
          contentType: false,
          processData: false,
          beforeSend() {
            buttonSave.prop('disabled', 'disabled');
            $('ul.text-danger').remove();
            $('*.has-danger').removeClass('has-danger');
          },
          success(response) {
            resetAttachmentForm();

            // inject new attachment in attachment list
            if (response.id) {
              /* eslint-disable */
              const row = `<tr>\
                <td class="col-md-3"><input type="checkbox" name="form[step6][attachments][]" value="${response.id}" checked="checked"> ${response.real_name}</td>\
                <td class="col-md-6">${response.file_name}</td>\
                <td class="col-md-2">${response.mime}</td>\
              </tr>`;
              /* eslint-enable */

              $('#product-attachment-file tbody').append(row);
              $('.js-options-no-attachments').addClass('hide');
              $('.js-options-with-attachments').removeClass('hide');
            }
          },
          error(response) {
            $.each(jQuery.parseJSON(response.responseText), (key, errors) => {
              let html = '<ul class="list-unstyled text-danger">';
              $.each(errors, (errorsKey, error) => {
                html += `<li>${error}</li>`;
              });
              html += '</ul>';

              $(`#form_step6_attachment_product_${key}`).parent().append(html);
              $(`#form_step6_attachment_product_${key}`).parent().addClass('has-danger');
            });
          },
          complete() {
            buttonSave.removeAttr('disabled');
          },
        });
      });
    },
  };
}());

/**
 * images product management
 */
window.imagesProduct = (function () {
  const dropZoneElem = $('#product-images-dropzone');
  const expanderElem = $('#product-images-container .dropzone-expander');

  function checkDropzoneMode() {
    if (!dropZoneElem.find('.dz-preview:not(.openfilemanager)').length) {
      dropZoneElem.removeClass('dz-started');
      dropZoneElem.find('.dz-preview.openfilemanager').hide();
    } else {
      dropZoneElem.find('.dz-preview.openfilemanager').show();
    }
  }

  return {
    toggleExpand() {
      if (expanderElem.hasClass('expand')) {
        dropZoneElem.css('height', 'auto');
        expanderElem.removeClass('expand').addClass('compress');
      } else {
        dropZoneElem.css('height', '');
        expanderElem.removeClass('compress').addClass('expand');
      }
    },
    displayExpander() {
      expanderElem.show();
    },
    hideExpander() {
      expanderElem.hide();
    },
    shouldDisplayExpander() {
      const oldHeight = dropZoneElem.css('height');

      dropZoneElem.css('height', '');
      const closedHeight = dropZoneElem.outerHeight();
      const realHeight = dropZoneElem[0].scrollHeight;

      if (oldHeight !== '0px') {
        dropZoneElem.css('height', oldHeight);
      }

      return (realHeight > closedHeight) && dropZoneElem.find('.dz-preview:not(.openfilemanager)').length;
    },
    updateExpander() {
      if (this.shouldDisplayExpander()) {
        this.displayExpander();
      }
    },
    initExpander() {
      if (this.shouldDisplayExpander()) {
        this.displayExpander();
        expanderElem.addClass('expand');
      }

      const self = this;
      $(document).on('click', '#product-images-container .dropzone-expander', () => {
        self.toggleExpand();
      });
    },
    init() {
      Dropzone.autoDiscover = false;
      const errorElem = $('#product-images-dropzone-error');

      // on click image, display custom form
      $(document).on('click', '#product-images-dropzone .dz-preview', function () {
        if (!$(this).attr('data-id')) {
          return;
        }
        formImagesProduct.form($(this).attr('data-id'));
      });

      const dropzoneOptions = {
        url: dropZoneElem.attr('url-upload'),
        paramName: 'form[file]',
        maxFilesize: dropZoneElem.attr('data-max-size'),
        addRemoveLinks: true,
        clickable: '.openfilemanager',
        thumbnailWidth: 250,
        thumbnailHeight: null,
        acceptedFiles: 'image/*',
        timeout: 0,
        dictRemoveFile: translate_javascripts.Delete,
        dictFileTooBig: translate_javascripts.ToLargeFile,
        dictCancelUpload: translate_javascripts.Delete,
        sending() {
          checkDropzoneMode();
          expanderElem.addClass('expand').click();
          errorElem.html('');
        },
        queuecomplete() {
          checkDropzoneMode();
          dropZoneElem.sortable('enable');
          imagesProduct.updateExpander();
        },
        processing() {
          dropZoneElem.sortable('disable');
        },
        success(file, response) {
          // manage error on uploaded file
          if (response.error !== 0) {
            errorElem.append($('<p></p>').text(`${file.name}: ${response.error}`));
            this.removeFile(file);
            return;
          }

          // define id image to file preview
          $(file.previewElement).attr('data-id', response.id);
          $(file.previewElement).attr('url-update', response.url_update);
          $(file.previewElement).attr('url-delete', response.url_delete);
          $(file.previewElement).addClass('ui-sortable-handle');
          if (response.cover === 1) {
            imagesProduct.updateDisplayCover(response.id);
          }
        },
        error(file, response) {
          let message = '';

          if ($.type(response) === 'undefined') {
            return;
          } if ($.type(response) === 'string') {
            message = response;
          } else if (response.message) {
            // eslint-disable-next-line
            message = response.message;
          }

          if (message === '') {
            return;
          }

          // append new error
          errorElem.append($('<p></p>').text(`${file.name}: ${message}`));

          // remove uploaded item
          this.removeFile(file);
        },
        init() {
          // if already images uploaded, mask drop file message
          if (dropZoneElem.find('.dz-preview:not(.openfilemanager)').length) {
            dropZoneElem.addClass('dz-started');
          } else {
            dropZoneElem.find('.dz-preview.openfilemanager').hide();
          }

          // init sortable
          dropZoneElem.sortable({
            items: 'div.dz-preview:not(.disabled)',
            opacity: 0.9,
            containment: 'parent',
            distance: 32,
            tolerance: 'pointer',
            cursorAt: {
              left: 64,
              top: 64,
            },
            cancel: '.disabled',
            stop() {
              let sort = {};
              $.each(dropZoneElem.find('.dz-preview:not(.disabled)'), (index, value) => {
                if (!$(value).attr('data-id')) {
                  sort = false;
                  return;
                }
                sort[$(value).attr('data-id')] = index + 1;
              });

              // if sortable ok, update it
              if (sort) {
                $.ajax({
                  type: 'POST',
                  url: dropZoneElem.attr('url-position'),
                  data: {
                    json: JSON.stringify(sort),
                  },
                });
              }
            },
            start(event, ui) {
              // init zindex
              dropZoneElem.find('.dz-preview').css('zIndex', 1);
              ui.item.css('zIndex', 10);
            },
          });

          dropZoneElem.disableSelection();
          imagesProduct.initExpander();
        },
      };

      dropZoneElem.dropzone(jQuery.extend(dropzoneOptions));
    },
    updateDisplayCover(idImage) {
      $('#product-images-dropzone .dz-preview .iscover').remove();
      $(`#product-images-dropzone .dz-preview[data-id="${idImage}"]`)
        .append(`<div class="iscover">${translate_javascripts.Cover}</div>`);
    },
    checkDropzoneMode() {
      checkDropzoneMode();
    },
    getOlderImageId() {
      // eslint-disable-next-line
      return Math.min.apply(Math, $('.dz-preview').map(function () {
        return $(this).data('id');
      }));
    },
  };
}());

window.formImagesProduct = (function () {
  const dropZoneElem = $('#product-images-dropzone');
  const formZoneElem = $('#product-images-form-container');

  // default state
  formZoneElem.hide();

  formZoneElem.magnificPopup({
    delegate: 'a.open-image',
    type: 'image',
  });

  function toggleColDropzone(enlarge) {
    const smallCol = 'col-md-8';
    const largeCol = 'col-md-12';

    if (enlarge === true) {
      dropZoneElem.removeClass(smallCol).addClass(largeCol);
    } else {
      dropZoneElem.removeClass(largeCol).addClass(smallCol);
    }
  }

  return {
    form(id) {
      dropZoneElem.find('.dz-preview.active').removeClass('active');
      dropZoneElem.find(`.dz-preview[data-id='${id}']`).addClass('active');
      if (!imagesProduct.shouldDisplayExpander()) {
        dropZoneElem.css('height', 'auto');
      }
      $.ajax({
        url: dropZoneElem.find(`.dz-preview[data-id='${id}']`).attr('url-update'),
        success(response) {
          formZoneElem.find('#product-images-form').html(response);
          form.switchLanguage($('#form_switch_language').val());
        },
        complete() {
          toggleColDropzone(false);
          formZoneElem.show();
          dropZoneElem.addClass('d-none d-md-block');
        },
      });
    },
    send(id) {
      $.ajax({
        type: 'POST',
        url: dropZoneElem.find(`.dz-preview[data-id='${id}']`).attr('url-update'),
        data: formZoneElem.find('textarea, input').serialize(),
        beforeSend() {
          formZoneElem.find('.actions button').prop('disabled', 'disabled');
          formZoneElem.find('ul.text-danger').remove();
          formZoneElem.find('*.has-danger').removeClass('has-danger');
        },
        success() {
          if (formZoneElem.find('#form_image_cover:checked').length) {
            imagesProduct.updateDisplayCover(id);
          }
        },
        error(response) {
          if (response && response.responseText) {
            $.each(jQuery.parseJSON(response.responseText), (key, errors) => {
              let html = '<ul class="list-unstyled text-danger">';
              $.each(errors, (errorsKey, error) => {
                html += `<li>${error}</li>`;
              });
              html += '</ul>';

              $(`#form_image_${key}`).parent().append(html);
              $(`#form_image_${key}`).parent().addClass('has-danger');
            });
          }
        },
        complete() {
          formZoneElem.find('.actions button').removeAttr('disabled');
        },
      });
    },
    delete(id) {
      modalConfirmation.create(translate_javascripts['Are you sure you want to delete this item?'], null, {
        onContinue() {
          $.ajax({
            url: dropZoneElem.find(`.dz-preview[data-id="${id}"]`).attr('url-delete'),
            complete() {
              formZoneElem.find('.close').click();
              const wasCover = !!dropZoneElem.find(`.dz-preview[data-id="${id}"] .iscover`).length;
              dropZoneElem.find(`.dz-preview[data-id="${id}"]`).remove();
              $(`.images .product-combination-image [value=${id}]`).parent().remove();
              imagesProduct.checkDropzoneMode();
              if (wasCover === true) {
                // The controller will choose the oldest image as the new cover.
                imagesProduct.updateDisplayCover(imagesProduct.getOlderImageId());
              }
            },
          });
        },
      }).show();
    },
    close() {
      toggleColDropzone(true);
      dropZoneElem.removeClass('d-none d-md-block');
      dropZoneElem.css('height', '');
      formZoneElem.find('#product-images-form').html('');
      formZoneElem.hide();
      dropZoneElem.find('.dz-preview.active').removeClass('active');
    },
  };
}());

/**
 * Price calculation
 */
window.priceCalculation = (function () {
  const priceHTElem = $('#form_step2_price');
  const priceHTShortcutElem = $('#form_step1_price_shortcut');
  const priceTTCElem = $('#form_step2_price_ttc');
  const priceTTCShorcutElem = $('#form_step1_price_ttc_shortcut');
  const ecoTaxElem = $('#form_step2_ecotax');
  const taxElem = $('#form_step2_id_tax_rules_group');
  const reTaxElem = $('#step2_id_tax_rules_group_rendered');
  const displayPricePrecision = priceHTElem.attr('data-display-price-precision');
  let ecoTaxRate = Number(ecoTaxElem.attr('data-eco-tax-rate'));

  if (isNaN(ecoTaxRate)) {
    ecoTaxRate = 0;
  } else {
    ecoTaxRate /= 100;
  }

  /**
   * Add taxes to a price
   * @param {Number} price - Price without tax
   * @param {Number[]} rates - Rates to apply
   * @param {Number} computationMethod The computation calculate method
   */
  function addTaxes(price, rates, computationMethod) {
    let priceWithTaxes = price;

    let i = 0;

    if (computationMethod === '0') {
      // eslint-disable-next-line
      for (i in rates) {
        priceWithTaxes *= (1.00 + parseFloat(rates[i]) / 100.00);
        break;
      }
    } else if (computationMethod === '1') {
      let rate = 0;

      // eslint-disable-next-line
      for (i in rates) {
        rate += rates[i];
      }
      priceWithTaxes *= (1.00 + parseFloat(rate) / 100.00);
    } else if (computationMethod === '2') {
      // eslint-disable-next-line
      for (i in rates) {
        priceWithTaxes *= (1.00 + parseFloat(rates[i]) / 100.00);
      }
    }

    return priceWithTaxes;
  }

  /**
   * Remove taxes from a price
   * @param {Number} price - Price with tax
   * @param {Number[]} rates - Rates to apply
   * @param {Number} computationMethod - The computation method
   */
  function removeTaxes(price, rates, computationMethod) {
    let i = 0;

    /* eslint-disable */
    if (computationMethod === '0') {
      for (i in rates) {
        price /= (1 + rates[i] / 100);
        break;
      }
    } else if (computationMethod === '1') {
      let rate = 0;

      for (i in rates) {
        rate += rates[i];
      }
      price /= (1 + rate / 100);
    } else if (computationMethod === '2') {
      for (i in rates) {
        price /= (1 + rates[i] / 100);
      }
    }
    /* eslint-enable */

    return price;
  }

  /**
   * @return {Number}
   */
  function getEcotaxTaxIncluded() {
    let ecoTax = Tools.parseFloatFromString(ecoTaxElem.val());

    if (isNaN(ecoTax)) {
      ecoTax = 0;
    }

    if (ecoTax === 0) {
      return ecoTax;
    }
    return ps_round(ecoTax, displayPricePrecision);
  }

  function getEcotaxTaxExcluded() {
    const ecoTax = Tools.parseFloatFromString(ecoTaxElem.val());

    if (isNaN(ecoTax) || ecoTax === 0) {
      return 0;
    }

    return ps_round(ecoTax / (1 + ecoTaxRate), displayPricePrecision);
  }

  return {

    getProductBasePrice() {
      return Tools.parseFloatFromString(priceHTElem.val());
    },

    getDisplayPricePrecision() {
      return displayPricePrecision;
    },

    init() {
      /** on update tax recalculate tax include price */
      taxElem.change(() => {
        if (reTaxElem.val() !== taxElem.val()) {
          reTaxElem.val(taxElem.val()).trigger('change');
        }

        priceCalculation.taxInclude();
        priceTTCElem.change();
      });

      reTaxElem.change(() => {
        taxElem.val(reTaxElem.val()).trigger('change');
      });

      /** update without tax price and shortcut price field on change */
      $('#form_step1_price_shortcut, #form_step2_price').keyup(function () {
        const price = priceCalculation.normalizePrice($(this).val());

        if ($(this).attr('id') === 'form_step1_price_shortcut') {
          $('#form_step2_price').val(price).change();
        } else {
          $('#form_step1_price_shortcut').val(price).change();
        }

        priceCalculation.taxInclude();
      });

      /** update HT price and shortcut price field on change */
      $('#form_step1_price_ttc_shortcut, #form_step2_price_ttc').keyup(function () {
        const price = priceCalculation.normalizePrice($(this).val());

        if ($(this).attr('id') === 'form_step1_price_ttc_shortcut') {
          $('#form_step2_price_ttc').val(price).change();
        } else {
          $('#form_step1_price_ttc_shortcut').val(price).change();
        }

        priceCalculation.taxExclude();
      });

      /** on price change, update final retails prices */
      $('#form_step2_price, #form_step2_price_ttc').change(() => {
        const taxExcludedPrice = priceCalculation.normalizePrice($('#form_step2_price').val());
        const taxIncludedPrice = priceCalculation.normalizePrice($('#form_step2_price_ttc').val());

        formatCurrencyCldr(taxExcludedPrice, (result) => {
          $('#final_retail_price_te').text(result);
        });
        formatCurrencyCldr(taxIncludedPrice, (result) => {
          $('#final_retail_price_ti').text(result);
        });
      });

      /** update HT price and shortcut price field on change */
      $('#form_step2_ecotax').keyup(() => {
        priceCalculation.taxExclude();
      });

      /** combinations : update TTC price field on HT change */
      $(document).on('blur', '.combination-form .attribute_priceTE', function () {
        priceCalculation.impactTaxInclude($(this));
        priceCalculation.impactFinalPrice($(this));
      });
      /** combinations : update HT price field on TTC change */
      $(document).on('blur', '.combination-form .attribute_priceTI', function () {
        priceCalculation.impactTaxExclude($(this));
        priceCalculation.impactFinalPrice($(this));
      });
      /** combinations : update price fields on ecotax change */
      $(document).on('blur', '.combination-form .attribute_ecotaxTi', function () {
        priceCalculation.impactPricesForEcotax($(this));
        priceCalculation.impactFinalPrice($(this));
      });

      /** combinations : update wholesale price, unity and price TE field on blur */
      // eslint-disable-next-line
      $(document).on('blur', '.combination-form .attribute_wholesale_price,.combination-form .attribute_unity,.combination-form .attribute_priceTE', function () {
        $(this).val(priceCalculation.normalizePrice($(this).val()));
      });

      priceCalculation.taxInclude();

      $('#form_step2_price, #form_step2_price_ttc').change();
    },

    /**
     * Converts a price string into a number
     * @param {String} price
     * @return {Number}
     */
    normalizePrice(price) {
      return Tools.parseFloatFromString(price, true);
    },

    /**
     * Adds taxes to a price
     * @param {Number} price Price without taxes
     * @return {Number} Price with added taxes
     */
    addCurrentTax(price) {
      const rates = this.getRates();
      const computationMethod = taxElem.find('option:selected').attr('data-computation-method');
      const priceWithTaxes = Number(ps_round(addTaxes(price, rates, computationMethod), displayPricePrecision));
      const ecotaxIncluded = Number(getEcotaxTaxIncluded());

      return priceWithTaxes + ecotaxIncluded;
    },

    /**
     * Calculates the price with taxes and updates the elements containing it
     */
    taxInclude() {
      const newPrice = truncateDecimals(
        this.addCurrentTax(this.normalizePrice(priceHTElem.val())),
        displayPricePrecision,
      );

      priceTTCElem.val(newPrice).change();
      priceTTCShorcutElem.val(newPrice).change();
    },

    /**
     * Removes taxes from a price
     * @param {Number} price Price with taxes
     * @return {Number} Price without taxes
     */
    removeCurrentTax(price) {
      const rates = this.getRates();
      const computationMethod = taxElem.find('option:selected').attr('data-computation-method');

      return ps_round(
        removeTaxes(
          ps_round(price - getEcotaxTaxIncluded(),
            displayPricePrecision,
          ),
          rates,
          computationMethod),
        displayPricePrecision,
      );
    },

    /**
     * Calculates the price without taxes and updates the elements containing it
     */
    taxExclude() {
      const newPrice = truncateDecimals(
        this.removeCurrentTax(this.normalizePrice(priceTTCElem.val())),
        displayPricePrecision,
      );

      priceHTElem.val(newPrice).change();
      priceHTShortcutElem.val(newPrice).change();
    },

    /**
     * Calculates and displays the impact on price (including tax) for a combination
     * @param {jQuery} obj
     */
    impactTaxInclude(obj) {
      const impactPriceTE = this.getImpactTEInputValue(obj);
      const impactPriceTI = this.computePriceTaxIncluded(impactPriceTE);

      this.updateImpactTIInput(impactPriceTI, obj);
    },

    /**
     * @param {jQuery} obj
     *
     * @returns {jQuery}
     */
    getImpactTIInput(obj) {
      return obj.closest('div[id^="combination_form_"]').find('input.attribute_priceTI');
    },

    /**
     * @param {jQuery} obj
     *
     * @returns {Number}
     */
    getImpactTIInputValue(obj) {
      const impactPriceTIInput = this.getImpactTIInput(obj);

      return Tools.parseFloatFromString(impactPriceTIInput.val());
    },

    /**
     * Computes the impact price tax included and update the related input
     *
     * @param {Number} impactPriceTI
     * @param {jQuery} obj
     */
    updateImpactTIInput(impactPriceTI, obj) {
      const impactPriceTIInput = this.getImpactTIInput(obj);
      impactPriceTIInput
        .val(impactPriceTI)
        .trigger('change');
    },

    /**
     * @param {jQuery} obj
     *
     * @returns {jQuery}
     */
    getImpactTEInput(obj) {
      return obj.closest('div[id^="combination_form_"]').find('input.attribute_priceTE');
    },

    /**
     * @param {jQuery} obj
     *
     * @returns {Number}
     */
    getImpactTEInputValue(obj) {
      const impactPriceTEInput = this.getImpactTEInput(obj);

      return Number(Tools.parseFloatFromString(impactPriceTEInput.val()));
    },

    /**
     * Updates the impact price tax excluded field, then update the impact tax included field accordingly
     *
     * @param {Number} impactPriceTE
     * @param {jQuery} obj
     */
    updateImpactTEInput(impactPriceTE, obj) {
      const impactPriceTEInput = this.getImpactTEInput(obj);
      impactPriceTEInput
        .val(impactPriceTE)
        .trigger('change');
      const impactPriceTI = this.computePriceTaxIncluded(impactPriceTE);
      this.updateImpactTIInput(impactPriceTI, obj);
    },

    /**
     * @param {Number} priceTE
     *
     * @returns {Number}
     */
    computePriceTaxIncluded(priceTE) {
      let priceTI = 0;

      if (!isNaN(priceTE) && priceTE !== 0) {
        const rates = this.getRates();
        const computationMethod = taxElem.find('option:selected').attr('data-computation-method');
        priceTI = ps_round(addTaxes(priceTE, rates, computationMethod), displayPricePrecision);
      }

      return priceTI;
    },

    /**
     * @param {Number} priceTI
     *
     * @returns {Number}
     */
    computePriceTaxExcluded(priceTI) {
      let priceTE = 0;

      if (!isNaN(priceTI) && priceTI !== 0) {
        const rates = this.getRates();
        const computationMethod = taxElem.find('option:selected').attr('data-computation-method');
        priceTE = ps_round(removeTaxes(priceTI, rates, computationMethod), displayPricePrecision);
      }

      return priceTE;
    },

    /**
     * Calculates and displays the final price for a combination
     * @param {jQuery} obj
     */
    impactFinalPrice(obj) {
      this.impactFinalPriceTaxExcluded(obj);
      this.impactFinalPriceTaxIncluded(obj);
    },

    /**
     * @param {jQuery} obj
     */
    impactFinalPriceTaxExcluded(obj) {
      const combinationForm = obj.closest('div[id^="combination_form_"]');

      const impactPriceTE = this.getImpactTEInputValue(obj);
      let ecotaxTE = this.getCombinationEcotaxTaxExcluded(obj);

      // If no ecotax for combination use the product's one
      if (ecotaxTE <= 0) {
        ecotaxTE = getEcotaxTaxExcluded();
      }

      const finalPriceContainer = combinationForm.find('.final-price');
      const productPriceTE = priceCalculation.getProductBasePrice();
      let finalPriceTE = productPriceTE + impactPriceTE + ecotaxTE;
      finalPriceTE = ps_round(finalPriceTE, displayPricePrecision);

      finalPriceContainer.html(finalPriceTE);
      finalPriceContainer.data('price', finalPriceTE);
    },

    /**
     * @param {jQuery} obj
     */
    impactFinalPriceTaxIncluded(obj) {
      const combinationForm = obj.closest('div[id^="combination_form_"]');

      const impactPriceTE = this.getImpactTEInputValue(obj);
      let ecotaxTI = this.getCombinationEcotaxTaxIncluded(obj);

      // If no ecotax for combination use the product's one
      if (ecotaxTI <= 0) {
        ecotaxTI = getEcotaxTaxIncluded();
      }

      const finalPriceTIContainer = combinationForm.find('.final-price-tax-included');
      const productPriceTE = priceCalculation.getProductBasePrice();
      let finalPriceTI = this.computePriceTaxIncluded(productPriceTE + impactPriceTE) + ecotaxTI;
      finalPriceTI = ps_round(finalPriceTI, displayPricePrecision);

      finalPriceTIContainer.html(finalPriceTI);
      finalPriceTIContainer.data('price', finalPriceTI);
    },

    /**
     * Calculates the impact on price so that the change on ecotax doesn't affect the final price
     * @param {jQuery} obj
     */
    impactPricesForEcotax(obj) {
      const finalPriceTIContainer = obj.closest('div[id^="combination_form_"]').find('.final-price-tax-included');
      const currentFinalPriceTI = Number(finalPriceTIContainer.data('price'));
      const productPrice = priceCalculation.getProductBasePrice();
      const productPriceTI = this.computePriceTaxIncluded(productPrice);
      let ecotaxTI = this.getCombinationEcotaxTaxIncluded(obj);

      // If no ecotax for combination use the product's one
      if (ecotaxTI <= 0) {
        ecotaxTI = getEcotaxTaxIncluded();
      }

      // Compute impact price tax excluded then update the price tax included
      let impactPriceTI = currentFinalPriceTI - ecotaxTI - productPriceTI;
      impactPriceTI = ps_round(impactPriceTI, displayPricePrecision);
      const impactPriceTE = this.computePriceTaxExcluded(impactPriceTI);

      this.updateImpactTEInput(impactPriceTE, obj);
    },

    /**
     * Calculates and displays the impact on price (excluding tax) for a combination
     * @param {jQuery} obj
     */
    impactTaxExclude(obj) {
      const impactPriceTI = this.getImpactTIInputValue(obj);
      const impactPriceTE = this.computePriceTaxExcluded(impactPriceTI);

      this.updateImpactTEInput(impactPriceTE, obj);
    },

    /**
     * @param {jQuery} obj
     *
     * @return {Number}
     */
    getCombinationEcotaxTaxExcluded(obj) {
      const ecoTaxTI = priceCalculation.getCombinationEcotaxTaxIncluded(obj);

      if (ecoTaxTI === 0) {
        return 0;
      }

      return ps_round(ecoTaxTI / (1 + ecoTaxRate), displayPricePrecision);
    },

    /**
     * @param {jQuery} obj
     *
     * @return {Number}
     */
    getCombinationEcotaxTaxIncluded(obj) {
      const ecotaxTIInput = obj.closest('div[id^="combination_form_"]').find('input.attribute_ecotaxTi');

      let ecoTaxTI = Tools.parseFloatFromString(ecotaxTIInput.val());

      if (isNaN(ecoTaxTI)) {
        ecoTaxTI = 0;
      }

      return ecoTaxTI;
    },

    /**
     * @param {int} attributeId
     * @returns {Number}
     */
    getCombinationEcotaxTaxIncludedById(attributeId) {
      const formFinalPriceLabel = $(`#combination_form_${attributeId}`).find('span.final-price');

      return priceCalculation.getCombinationEcotaxTaxIncluded(formFinalPriceLabel);
    },

    /**
     * @param {int} attributeId
     *
     * @returns {Number}
     */
    getCombinationFinalPriceTaxExcludedById(attributeId) {
      const combinationForm = $(`#combination_form_${attributeId}`);
      const formFinalPriceLabel = combinationForm.find('span.final-price');
      let combinationEcotaxTE = priceCalculation.getCombinationEcotaxTaxExcluded(formFinalPriceLabel);

      if (combinationEcotaxTE <= 0) {
        combinationEcotaxTE = priceCalculation.getProductEcotaxTaxExcluded();
      }

      const impactPriceTEInput = combinationForm.find('.attribute_priceTE');
      const impactPriceTE = Tools.parseFloatFromString(impactPriceTEInput.val());

      // Compute final price and update field
      const productPrice = priceCalculation.getProductBasePrice();
      let finalPrice = productPrice + combinationEcotaxTE + impactPriceTE;
      finalPrice = ps_round(finalPrice, displayPricePrecision);

      return finalPrice;
    },

    /**
     * @return {Number}
     */
    getProductEcotaxTaxExcluded() {
      const ecoTax = priceCalculation.getProductEcotaxTaxIncluded();

      if (ecoTax === 0) {
        return ecoTax;
      }

      return ps_round(ecoTax / (1 + ecoTaxRate), displayPricePrecision);
    },

    /**
     * @return {Number}
     */
    getProductEcotaxTaxIncluded() {
      let ecoTax = Tools.parseFloatFromString(ecoTaxElem.val());

      if (isNaN(ecoTax)) {
        ecoTax = 0;
      }

      return ecoTax;
    },

    /**
     * Returns the tax rates that apply
     * @return {Number[]}
     */
    getRates() {
      return taxElem
        .find('option:selected')
        .attr('data-rates')
        .split(',')
        .map((rate) => Tools.parseFloatFromString(rate, true));
    },
  };
}());

/**
 * Manage seo
 */
window.seo = (function () {
  const redirectTypeElem = $('#form_step5_redirect_type');
  const productRedirect = $('#id-product-redirected');

  /** Hide or show the input product selector */
  function hideShowRedirectToProduct() {
    redirectTypeValue = redirectTypeElem.val();
    if (redirectTypeValue === '404'
      || redirectTypeValue === '410'
      || redirectTypeValue === 'default'
      || redirectTypeValue === '200-displayed'
      || redirectTypeValue === '404-displayed'
      || redirectTypeValue === '410-displayed'
    ) {
      $('#id-product-redirected').hide();
    } else {
      updateRemoteUrl();
      $('#id-product-redirected').show();
    }
  }

  function updateRemoteUrl() {
    switch (redirectTypeElem.val()) {
      case '301-category':
      case '302-category':
        productRedirect.find('label').html(redirectTypeElem.attr('data-labelcategory'));
        productRedirect.find('input').attr('placeholder', redirectTypeElem.attr('data-placeholdercategory'));
        productRedirect.find('.typeahead-hint').text(redirectTypeElem.attr('data-hintcategory'));
        break;
      default:
        productRedirect.find('label').html(redirectTypeElem.attr('data-labelproduct'));
        productRedirect.find('input').attr('placeholder', redirectTypeElem.attr('data-placeholderproduct'));
        productRedirect.find('.typeahead-hint').text('');
    }

    productRedirect.find('.autocomplete-search').attr(
      'data-remoteurl',
      redirectTypeElem.find('option:selected').data('remoteurl'),
    );
    productRedirect.find('.autocomplete-search').trigger('buildTypeahead');
  }

  /** Update friendly URL */
  const updateFriendlyUrl = function (elem) {
    /** Attr name equals "form[step1][name][1]".
       * We need in this string the second integer */
    const idLang = elem.attr('name').match(/\d+/g)[1];
    $(`#form_step5_link_rewrite_${idLang}`).val(str2url(elem.val(), 'UTF-8'));
  };

  return {
    init() {
      hideShowRedirectToProduct();
      updateRemoteUrl();

      /** On redirect type select change */
      redirectTypeElem.change(() => {
        productRedirect.find('#form_step5_id_type_redirected-data').html('');
        hideShowRedirectToProduct();
      });

      /** On product title change, update friendly URL */
      $('#form_step1_names.friendly-url-force-update input').keyup(function () {
        updateFriendlyUrl($(this));
      });

      /** Reset all languages title to friendly url */
      $('#seo-url-regenerate').click(() => {
        $.each($('#form_step1_names input'), function () {
          updateFriendlyUrl($(this));
        });
      });
    },
    onSave() {
      // check all friendly URLs have been filled. If not, fill them.
      $('input[id^="form_step5_link_rewrite_"]', '#form_step5_link_rewrite').each(function () {
        const elem = $(this);

        if (elem.val().length === 0) {
          const idLang = elem.attr('name').match(/\d+/g)[1];
          updateFriendlyUrl($(`#form_step1_name_${idLang}`));
        }
      });
    },
  };
}());

/**
 * Tags management
 */
window.tags = (function () {
  return {
    init() {
      $('#form_step6_tags .tokenfield').tokenfield({
        minWidth: '768px',
      });
    },
  };
}());

window.recommendedModules = (function () {
  return {
    init() {
      this.moduleActionMenuLinkSelectors = 'button.module_action_menu_install, button.module_action_menu_enable, '
        // eslint-disable-next-line
        + 'button.module_action_menu_uninstall, button.module_action_menu_disable, button.module_action_menu_reset, button.module_action_menu_update';
      $(this.moduleActionMenuLinkSelectors).on('module_card_action_event', this.saveProduct);
    },
    saveProduct() {
      form.send();
    },
  };
}());
