import { required, numeric, email, max, min } from 'vee-validate/dist/rules';
import getNumbersFromStringWithMask from '@assets/js/getNumbersFromStringWithMask';
import getOnlyNumbersFromString from '@assets/js/getOnlyNumbersFromString';

import { isValid, parse } from 'date-fns';

const min_value = {
  validate(value, { min }) {
    value = getNumbersFromStringWithMask(value);

    return value >= min;
  },
  params: ['min'],
};

const max_value = {
  validate(value, { max }) {
    value = getNumbersFromStringWithMask(value);
    return value <= max;
  },
  params: ['max'],
};

const cep = {
  validate(value) {
    const cepRegex = /^[0-9]{5}-[0-9]{3}$/;
    return cepRegex.test(value);
  },
};

const minmax_number = {
  validate(value, { min, max }) {
    value = getNumbersFromStringWithMask(value);

    return value >= min && value <= max;
  },
  params: ['min', 'max'],
};

const target_bigger_than_reference = {
  validate(value, { reference }) {
    const targetValue = getNumbersFromStringWithMask(value);

    if (targetValue) {
      const referenceValue = getNumbersFromStringWithMask(reference);
      return targetValue > referenceValue;
    }
  },
  params: ['reference'],
};

const target_is_duplicated = {
  validate(value, { data, key }) {
    const hasKey = typeof key !== 'undefined';
    const normalizeValue = value =>
      String(value)
        .trim()
        .toUpperCase();
    const isDuplicated = data.filter(
      dataItem => normalizeValue(hasKey ? dataItem[key] : dataItem) === normalizeValue(value)
    );
    return isDuplicated.length <= 1;
  },
  params: ['data', 'key'],
};

const module_is_duplicated = {
  validate(_, { data: modules, index, keys }) {
    const currentLayout = modules[index].layout_id;
    const currentPosition = modules[index].position;
    let isDuplicated = false,
      totalDuplicatedKeys = 0;

    for (let interactionIndex = 0; interactionIndex < modules.length; interactionIndex++) {
      if (interactionIndex === index) {
        continue;
      }

      const isApp = modules[interactionIndex].position === 'content_app';
      const isLayoutDuplicated = modules[interactionIndex].layout_id === currentLayout;

      switch (currentPosition) {
        case 'content_app':
          if (isApp && isLayoutDuplicated) {
            isDuplicated = true;
          }
          break;

        default:
          if (!isApp && isLayoutDuplicated) {
            isDuplicated = true;
          }
      }

      if (keys && isDuplicated) {
        keys.forEach(key => {
          const isNotFieldDuplicated = modules[index][key] !== modules[interactionIndex][key];

          if (isNotFieldDuplicated) {
            return true;
          }

          totalDuplicatedKeys++;
        });

        if (totalDuplicatedKeys === keys.length) {
          return false;
        }

        return true;
      }
    }

    return isDuplicated ? false : true;
  },
  params: ['data', 'index', 'keys'],
};

const target_is_mandatory = {
  validate(_, { data, key }) {
    const hasKey = typeof key !== 'undefined';

    const isMandatory = data.filter(dataItem => hasKey && parseInt(dataItem[key]) === 1);

    return isMandatory.length == 1;
  },
  params: ['data', 'key'],
};

const cpf = {
  validate(value) {
    const cpf = String(getOnlyNumbersFromString(value));

    let numeros, digitos, soma, i, resultado, digitos_iguais;
    digitos_iguais = 1;
    if (cpf.length < 11) return false;
    for (i = 0; i < cpf.length - 1; i++)
      if (cpf.charAt(i) != cpf.charAt(i + 1)) {
        digitos_iguais = 0;
        break;
      }
    if (!digitos_iguais) {
      numeros = cpf.substring(0, 9);
      digitos = cpf.substring(9);
      soma = 0;
      for (i = 10; i > 1; i--) soma += numeros.charAt(10 - i) * i;
      resultado = soma % 11 < 2 ? 0 : 11 - (soma % 11);
      if (resultado != digitos.charAt(0)) return false;
      numeros = cpf.substring(0, 10);
      soma = 0;
      for (i = 11; i > 1; i--) soma += numeros.charAt(11 - i) * i;
      resultado = soma % 11 < 2 ? 0 : 11 - (soma % 11);
      if (resultado != digitos.charAt(1)) return false;
      return true;
    } else return false;
  },
};

const cnpj = {
  validate(value) {
    value = String(getOnlyNumbersFromString(value));

    let numeros, digitos, soma, i, resultado, pos, tamanho, digitos_iguais;
    if (value.length == 0) {
      return false;
    }

    value = value.replace(/\D+/g, '');
    digitos_iguais = 1;

    for (i = 0; i < value.length - 1; i++)
      if (value.charAt(i) != value.charAt(i + 1)) {
        digitos_iguais = 0;
        break;
      }
    if (digitos_iguais) return false;

    tamanho = value.length - 2;
    numeros = value.substring(0, tamanho);
    digitos = value.substring(tamanho);
    soma = 0;
    pos = tamanho - 7;
    for (i = tamanho; i >= 1; i--) {
      soma += numeros.charAt(tamanho - i) * pos--;
      if (pos < 2) pos = 9;
    }
    resultado = soma % 11 < 2 ? 0 : 11 - (soma % 11);
    if (resultado != digitos.charAt(0)) {
      return false;
    }
    tamanho = tamanho + 1;
    numeros = value.substring(0, tamanho);
    soma = 0;
    pos = tamanho - 7;
    for (i = tamanho; i >= 1; i--) {
      soma += numeros.charAt(tamanho - i) * pos--;
      if (pos < 2) pos = 9;
    }

    resultado = soma % 11 < 2 ? 0 : 11 - (soma % 11);

    return resultado == digitos.charAt(1);
  },
};

const telephone = {
  validate(value) {
    return /^(|\([0-9]{2}\)[\s][0-9]{4}-[0-9]{4})$/.test(value);
  },
};

const cellphone = {
  validate(value) {
    return /^(|\([0-9]{2}\)[\s][0-9]{4,5}-[0-9]{4})$/.test(value);
  },
};

const withoutDot = {
  validate(value) {
    return /^[^.]*$/.test(value);
  },
};

const date = {
  validate(value) {
    if (/^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/.test(value)) {
      const parsedDate = parse(value, 'dd/MM/yyyy', new Date());
      const result = isValid(parsedDate);

      return result;
    }
    return;
  },
};

const date_bigger_than_today = {
  validate(value) {
    const [day, month, year] = value.split('/');
    const date = new Date(Number(year), Number(month) - 1, Number(day));
    const today = new Date();

    return today.getTime() >= date.getTime();
  },
};

const date_smaller_than_today = {
  validate(_, { data: value }) {
    const [day, month, year] = value.split('/');
    const date = new Date(Number(year), Number(month) - 1, Number(day));
    const today = new Date();

    return today.getTime() < date.getTime();
  },
  params: ['data'],
};

const date_greater_than_start = {
  validate(value, { start: valueStart }) {
    const start_date = new Date(
      valueStart
        .split('/')
        .reverse()
        .join('-')
    );
    const end_date = new Date(
      value
        .split('/')
        .reverse()
        .join('-')
    );

    return end_date >= start_date;
  },
  params: ['start'],
};

const time_greater_than_start = {
  validate(value, { start: valueStart }) {
    const [hoursStart, minutesStart] = valueStart.split(':').map(Number);
    const [hoursEnd, minutesEnd] = value.split(':').map(Number);

    const totalMinutesStart = hoursStart * 60 + minutesStart;
    const totalMinutesEnd = hoursEnd * 60 + minutesEnd;

    return totalMinutesEnd >= totalMinutesStart;
  },
  params: ['start'],
};

let dynamicMessage = 'Existem erros nos campos!';
const handlerValidation = {
  validate(_, { valid, message }) {
    dynamicMessage = message || dynamicMessage;
    return typeof valid == 'undefined' ? [] : valid;
  },
  params: ['valid', 'message'],
  message() {
    return dynamicMessage;
  },
};

const groupCheckbox = {
  validate(value, { max }) {
    if (value > 0 || max > 0) {
      value = true;
    } else {
      value = false;
    }
    return value;
  },
  params: ['min', 'max'],
};

const validations = {
  required,
  numeric,
  email,
  max,
  min,
  max_value,
  min_value,
  cep,
  minmax_number,
  target_bigger_than_reference,
  cpf,
  cnpj,
  telephone,
  cellphone,
  withoutDot,
  target_is_duplicated,
  module_is_duplicated,
  date,
  date_bigger_than_today,
  date_smaller_than_today,
  date_greater_than_start,
  time_greater_than_start,
  target_is_mandatory,
  handlerValidation,
  groupCheckbox,
};

export default validations;
