import '@babel/polyfill';
import axios from 'axios';
import { IbgeCities, IbgeCitiesApp } from './ibgecities';
import { searchPostcode, searchPostcodeApp } from './postcode-search';
import { renderHtml } from './helpers';

const BASE_URL = document.getElementById('base-urls').dataset.baseUrlLoja;

class Postcode {
  constructor(postcode, postcodeContent, container, options = {}) {
    this.baseUrl = BASE_URL;
    this.previousPostcodeValue = '';

    this.container = container;
    this.postcode = postcode;
    this.postcodeParent = this.postcode.parentElement;
    this.postcodeContent = postcodeContent;

    this.dontKnow = options.dontKnow;
    this.validateClasses = options.validateClasses;
    this.hiddenClass = options.hiddenClass;
    this.disableClasses = options.disableClasses;
    this.loading = options.loading;
    this.ibgeCitiesElements = options.ibgeCitiesElements;

    this.ibgeCities = this.getIbgeCities();

    this.init();
    this.initEvents();
  }
  init() {}
  initEvents() {
    this.postcode.addEventListener('keyup', () => {
      const LENGTH = this.postcode.value.replace(/[-.]/g, '').length;
      if (LENGTH === 8) {
        this.postcodeSearch();
      }
    });

    this.postcode.addEventListener('blur', () => this.clearPostcodeInputError());

    if (this.postcode.value) {
      if (!this.postcodeContent.querySelector('.address_1').value) {
        this.postcode.dispatchEvent(new Event('keyup'));
      } else {
        this.show(this.postcodeContent);
      }
    }

    this.dontKnowMyPostcode();
  }
  getIbgeCities() {
    const { zoneId, codigoMunicipio, city } = this.ibgeCitiesElements;
    if (!codigoMunicipio) return false;

    return new IbgeCities(zoneId, codigoMunicipio, city, { baseUrl: this.baseUrl });
  }
  dontKnowMyPostcode() {
    this.dontKnow.addEventListener('click', e => {
      e.preventDefault();
      new searchPostcode(this.postcode, { baseUrl: this.baseUrl, hiddenClass: this.hiddenClass });
    });
  }
  clearPostcodeInputError() {
    this.postcode.classList.remove('form-error');

    const ERROR = this.postcodeParent.querySelector('span.form-error');
    if (!ERROR) return false;
    this.postcodeParent.removeChild(ERROR);
  }
  displayPostcodeInputError(error) {
    this.clearPostcodeInputError();
    const ERROR = renderHtml(`<span id="postcode-error" class="form-error">${error}</span>`);

    this.postcode.classList.remove('form-success');
    this.postcode.classList.add('form-error');
    this.postcodeParent.insertBefore(ERROR, this.postcode.nextElementSibling);
  }
  loadFormAddressInfo(dados) {
    for (let key in dados) {
      const ENTRY = this.postcodeContent.querySelector('.' + key);
      if (!ENTRY) continue;
      ENTRY.removeAttribute('readonly');
      if (!dados[key]) continue;

      ENTRY.value = dados[key];
      ENTRY.setAttribute('readonly', 'readonly');

      if (window.blockSelectReadonly) {
        window.blockSelectReadonly(this.postcodeContent);
      }
    }
    this.clearValidateClassesAndErrors();
  }
  clearFormAddressInfo() {
    const FORM_CONTROLS = this.getPostcodeContentFields();
    for (let index = 0; index < FORM_CONTROLS.length; index++) {
      const ENTRY = FORM_CONTROLS[index];
      ENTRY.value = '';
      ENTRY.removeAttribute('readonly');

      if (window.blockSelectReadonly) {
        window.blockSelectReadonly(this.postcodeContent);
      }
    }
    this.clearValidateClassesAndErrors();
  }
  getPostcodeContentFields() {
    return this.postcodeContent.querySelectorAll('input, select, textarea');
  }
  /**
   * @param {Array} arrayOfClasses array contendo as classes sem ponto, ex: ['classe1', 'classe2']
   * @return {String} ex: '.classe1, .classe2'
   */
  getSelectorFromArray(arrayOfClasses) {
    return arrayOfClasses.map(stringClass => '.' + stringClass).join();
  }
  addClasses(element, arrayOfClasses) {
    element.classList.add.apply(element.classList, arrayOfClasses);
  }
  removeClasses(element, arrayOfClasses) {
    element.classList.remove.apply(element.classList, arrayOfClasses);
  }
  isInputErrorMessage(element) {
    return element.id.indexOf('-error') && element.tagName === 'SPAN';
  }
  clearValidateClassesAndErrors() {
    const FORM_CONTROLS = this.postcodeContent.querySelectorAll(this.getSelectorFromArray(this.validateClasses));
    for (let index = 0; index < FORM_CONTROLS.length; index++) {
      const CONTROL = FORM_CONTROLS[index];
      if (this.isInputErrorMessage(CONTROL)) {
        CONTROL.parentNode.removeChild(CONTROL);
      }
      this.removeClasses(CONTROL, this.validateClasses);
    }
  }
  getAddressInfo() {
    return axios({
      headers: { 'content-type': 'application/x-www-form-urlencoded' },
      url: this.baseUrl + 'index.php?route=postcode/postcode/search',
      method: 'post',
      responseType: 'json',
      timeout: 10000,
      data: 'cep=' + this.postcode.value,
    });
  }
  postcodeSearch() {
    if (this.postcode.value === this.previousPostcodeValue) return false;

    this.show(this.loading);

    this.getAddressInfo()
      .then(({ data }) => {
        const { dados, error } = data,
          CITY_DATA = {};

        if (dados) {
          this.previousPostcodeValue = this.postcode.value;
          delete dados['postcode'];

          this.loadFormAddressInfo(dados);

          CITY_DATA.codigo_municipio = dados.codigo_municipio;
          CITY_DATA.city = dados.city;
        }

        if (error) {
          this.previousPostcodeValue = '';
          this.clearFormAddressInfo();

          // tem necessidade ???
          // const { warning, notification_type } = data;
          // if (typeof notificationMsg !== 'undefined') {
          //   notificationMsg(warning, 'error', notification_type);
          // }

          this.displayPostcodeInputError(error);
        }

        if (this.ibgeCities) {
          this.ibgeCities.loadIbgeCitiesList(CITY_DATA);
        }
      })
      .catch(error => {
        this.previousPostcodeValue = '';
        notificationMsg('Erro ao recuperar os dados de endereço, preencha manualmente', 'error', 0);
        console.error(error);
      })
      .finally(() => {
        this.show(this.postcodeContent);
        this.hide(this.loading);
      });
  }
  show(element) {
    element.classList.remove(this.hiddenClass);
  }
  hide(element) {
    element.classList.add(this.hiddenClass);
  }
}

class PostcodeApp extends Postcode {
  getIbgeCities() {
    const { zoneId, codigoMunicipio, city } = this.ibgeCitiesElements;
    if (!codigoMunicipio) return false;

    return new IbgeCitiesApp(zoneId, codigoMunicipio, city, { baseUrl: this.baseUrl });
  }
  dontKnowMyPostcode() {
    new searchPostcodeApp(this.postcode, { baseUrl: this.baseUrl, hiddenClass: this.hiddenClass });
  }
  clearPostcodeInputError() {
    this.postcodeParent.classList.remove('error');

    const ERROR = this.postcodeParent.querySelector('.ftr-field__error');
    if (!ERROR) return false;
    this.postcodeParent.removeChild(ERROR);
  }
  displayPostcodeInputError(error) {
    const ERROR = renderHtml(`<span class="ftr-field__error">${error}</span>`);

    this.postcodeParent.classList.add('error');
    this.postcodeParent.appendChild(ERROR);
  }
  loadFormAddressInfo(dados) {
    super.loadFormAddressInfo(dados);
    for (let key in dados) {
      const ENTRY = this.postcodeContent.querySelector('.' + key);
      if (!ENTRY) continue;

      ENTRY.dispatchEvent(new Event('focus'));
      this.addClasses(ENTRY.parentElement, this.disableClasses);
    }
  }
  clearFormAddressInfo() {
    super.clearFormAddressInfo();
    const FORM_CONTROLS = this.getPostcodeContentFields();
    for (let index = 0; index < FORM_CONTROLS.length; index++) {
      const ENTRY = FORM_CONTROLS[index];
      ENTRY.dispatchEvent(new Event('blur'));
      this.removeClasses(ENTRY.parentElement, this.disableClasses);
    }
  }
  isInputErrorMessage(element) {
    return element.classList.contains('ftr-field__error') && element.tagName === 'SPAN';
  }
}

//==============================================================================

function isApp(element) {
  return element.classList.contains('ftr-field__entry');
}

window.initPostcode = function(context) {
  context = context || document;

  const POSTCODE = context.querySelectorAll('.js-postcode-search'),
    POSTCODE_FRETE = context.querySelector('.js-frete .js-postcode-frete-search');

  if (POSTCODE_FRETE) {
    const CONTAINER_FRETE = POSTCODE_FRETE.closest('.js-frete'),
    dontKnow = CONTAINER_FRETE.querySelector('.js-postcode-address');
    if (isApp(POSTCODE_FRETE)) {
      new searchPostcodeApp(POSTCODE_FRETE, { baseUrl: BASE_URL, hiddenClass: 'ftr-none' });
    } else {
      dontKnow.addEventListener('click', e => {
        e.preventDefault();
        new searchPostcode(POSTCODE_FRETE, { baseUrl: BASE_URL, hiddenClass: 'hidden' });
      });
    }
  }

  for (let index = 0; index < POSTCODE.length; index++) {
    const INPUT_POSTCODE = POSTCODE[index],
      CONTAINER = INPUT_POSTCODE.closest('.js-address'),
      POSTCODE_CONTENT = CONTAINER.querySelector('.js-postcode-content'),
      dontKnow = CONTAINER.querySelector('.js-postcode-address'),
      ibgeCitiesElements = {
        zoneId: POSTCODE_CONTENT.querySelector('.js-city-search'),
        codigoMunicipio: POSTCODE_CONTENT.querySelector('.codigo-municipio'),
        city: POSTCODE_CONTENT.querySelector('.city'),
      };

    if (isApp(INPUT_POSTCODE)) {
      new PostcodeApp(INPUT_POSTCODE, POSTCODE_CONTENT, CONTAINER, {
        validateClasses: ['error', 'ftr-field__error'],
        hiddenClass: 'ftr-none',
        disableClasses: ['ftr-select--disabled', 'ftr-js-select--disabled', 'written'],
        loading: document.querySelector('.ftr-loading-bar'),
        dontKnow,
        ibgeCitiesElements,
      });
    } else {
      new Postcode(INPUT_POSTCODE, POSTCODE_CONTENT, CONTAINER, {
        validateClasses: ['form-error', 'form-success'],
        hiddenClass: 'hidden',
        disableClasses: [],
        loading: CONTAINER.querySelector('.js-postcode-loading'),
        dontKnow,
        ibgeCitiesElements,
      });
    }
  }
};

if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', () => {
    window.initPostcode();
  });
} else {
  window.initPostcode();
}

/*

regras

O input do cep deve ter a classe  .js-postcode-search
O link "Não sei meu cep" deve ter a classe .js-postcode-address
Adicionar a class .js-address em um elemento quer seja pai tanto do input.js-postcode-search quanto do .js-postcode-content

o select de estado deve ter um data-codigo-municipio com o codigo do municipio
todos os inputs e selects detro do postcode-content devem ter as classes correspondentes ao retorno do postcode:
rua    .address_1
bairro .address_2
estado .zone_id (o select do estado tem que ter um data-codigo-municipio)
cidade .codigo-municipio

.tipo_logradouro
.logradouro
.city

.cities-list no app container para as cidades .ftr-js-select_content

*/
