package com.ejie.ad74a.util;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UtilLiquidaciones {
	private static Logger logger = LoggerFactory.getLogger(UtilLiquidaciones.class);

	private UtilLiquidaciones() {
	}

	/**
	 * Calcula la fecha de emision con las siguientes premisas:
	 * 
	 * Fecha actual del sistema, excepto cuando se emiten en enero los cargos de
	 * diciembre, es decir, si la mensualidad tratada es diciembre del ano X. En
	 * este caso serÃ¡ 31/12/X.
	 * 
	 * @param cargoMensual
	 * @return
	 */
	public static Date getFechaEmision(int anyo, int mes) {

		Integer mesActual = LocalDate.now().getMonthValue();

		LocalDate localDateFechaEmision = (mesActual == 1 && mes == 12) ? LocalDate.of(anyo - 1, 12, 31)
				: LocalDate.now();

		return UtilDates.formatLocalDateToDate(localDateFechaEmision);
	}

	/**
	 * Devuelve referencia liquidacion formada por el ejercicio_00 &
	 * Num_Liquidacion_00 (7 posiciones con ceros por la izquierda).
	 * 
	 * @param ejercicio
	 * @param numLiquidacion
	 * @return
	 */
	public static String getReferenciaLiquidacion(Integer ejercicio, Integer numLiquidacion) {
		return StringUtils.join(new Object[] { ejercicio, StringUtils.leftPad(numLiquidacion.toString(), 7, '0') });
	}

	/**
	 * Devuelve idTerritorio en base a idProvincia segun codificaciÃ³n de SIPCA: 1
	 * â€“ Ã�lava/Araba (01) 2 â€“ Gipuzkoa (20) 3 â€“ Bizkaia (48)
	 * 
	 * @param idProvincia
	 * @return
	 */
	public static Integer getIdTerritorio(String idProvincia) {
		switch (idProvincia) {
		case "01":
			return 1;
		case "1":
			return 1;
		case "20":
			return 2;
		case "48":
			return 3;
		default:
			return null;
		}
	}

	/**
	 * Devuelve el tipo tercero en base al idTipoIdentificadorTitular de la cuenta
	 * en AD74A Tipo de identificador en SIPCA. 1-CIF, 2-DNI/NIE, 3-Pasaporte Tipo
	 * identificador en AD74A. 1-->DNI/NAN; 2-->CIF/IFK; 3-->NIE/AIZ;
	 * 4-->Pasaporte/Pasaportea; 5-->Otros/Beste Batzuk
	 * 
	 * @param idTipoIdenTitular
	 * @return
	 */
	public static Integer getTipoTercero(String idTipoIdenTitular) {

		if (null != idTipoIdenTitular) {
			switch (idTipoIdenTitular) {
			case "1":
				return 2;
			case "2":
				return 1;
			case "3":
				return 2;
			case "4":
				return 3;
			case "5":
				return 3;
			default:
				return Integer.valueOf(idTipoIdenTitular);
			}
		}

		return 0;

	}

	/**
	 * Calcula el digito de control de un CSB 57 (Consejo Superior Bancario) El
	 * digito de control del CSB se calcula de la siguiente forma: - Sumar emisor(8)
	 * + sufijo (3) + referencia(11) + identificacion(6) + importe en centeuros -
	 * Dividir por 97 el resultado de la suma - Obtener los dos primeros decimales
	 * de la division - El digito de control es (100 - los dos decimales)
	 */
	public static String getDigitoControlCSB507(String emisor, String sufijo, String referencia, String identificacion,
			String importeCenteuros) {
		try {
			long lngEmisor = Long.parseLong(emisor);
			long lngSufijo = Long.parseLong(sufijo);
			long lngReferencia = Long.parseLong(referencia.substring(0, 11)); // Solo 11 digitos de la referencia
			long lngIdentificacion = Long.parseLong(identificacion);
			long lngImporte = Long.parseLong(importeCenteuros);
			// Obtener la suma
			long suma = lngEmisor + lngSufijo + lngReferencia + lngIdentificacion + lngImporte;
			// Obtener los decimales de la division
			long resto = suma % 97;
			double decimales = resto / 97.0; // OJO!!! No poner 97 sin mas ya que JAVA utilizaria integer
			// y devolveria 0.0
			// Obtener los dos primeros digitos de la division
			String strDecimales = Double.toString(decimales);
			int comaIndx = strDecimales.indexOf('.');
			if (comaIndx > 0) {
				strDecimales = strDecimales.substring(comaIndx + 1);
			} else {
				comaIndx = strDecimales.indexOf(',');
				if (comaIndx > 0)
					strDecimales = strDecimales.substring(comaIndx + 1);
			}
			if (Double.parseDouble(strDecimales) == 0) {
				return "00";
			} else if (strDecimales.length() == 1) {
				strDecimales = strDecimales + "0";
			} else {
				strDecimales = strDecimales.substring(0, 2);
			}
			int digitoControl = 100 - Integer.parseInt(strDecimales);
			if (digitoControl < 10)
				return "0" + digitoControl;
			return Integer.toString(digitoControl);
		} catch (Exception ex) {
			logger.warn("Error en getDigitoControlCSB507", ex);
			return "EX"; // Indica que ha habido una exception al generar el digito de control
		}
	}

	public static boolean isValidIban(String iban) {
		boolean resultado = false;

		if (iban != null) {
			iban = iban.replaceAll("\\s", "");// Quitar espacios
			if (iban.length() < 24) {
				// No tiene los 24 caracteres de un Iban
				return false;
			}
			if (validarDC(iban) && validarIban(iban)) {
				return true;
			}
		}
		return resultado;
	}

	private static boolean validarDC(String iban) {
		int digIni = 0;
		if (iban.length() == 24) {
			digIni = 4;
		} else if (iban.length() != 20) {
			return false;
		}

		String banco = iban.substring(digIni, digIni + 4);
		String sucursal = iban.substring(digIni + 4, digIni + 8);
		String dc = iban.substring(digIni + 8, digIni + 10);
		String cuenta = iban.substring(digIni + 10);

		String ccc = banco + sucursal + dc + cuenta;

		if (!ccc.matches("[0-9]{20}")) {
			return false;
		} else {
			return validarCodigoControl(banco, sucursal, dc, cuenta);
		}
	}

	private static boolean validarCodigoControl(String banco, String sucursal, String dc, String cuenta) {

		int[] valores = { 1, 2, 4, 8, 5, 10, 9, 7, 3, 6 };
		int control = 0;

		for (int i = 0; i <= 9; i++) {
			control += Integer.parseInt(String.valueOf(cuenta.charAt(i))) * valores[i];
		}

		control = 11 - (control % 11);
		control = control == 11 ? 0 : (control == 10 ? 1 : control);

		if (control != Integer.parseInt(String.valueOf(dc.charAt(1)))) {
			return false;
		}

		control = 0;
		String zbs = "00" + banco + sucursal;

		for (int i = 0; i <= 9; i++) {
			control += Integer.parseInt(String.valueOf(zbs.charAt(i))) * valores[i];
		}

		control = 11 - (control % 11);
		control = control == 11 ? 0 : (control == 10 ? 1 : control);

		return control == Integer.parseInt(String.valueOf(dc.charAt(0)));
	}

	private static boolean validarIban(String iban) {
		iban = iban.toUpperCase().trim().replaceAll("\\s", "");

		if (iban.length() != 24) {
			return false;
		}

		char letra1 = iban.charAt(0);
		char letra2 = iban.charAt(1);
		int num1 = getNumIBAN(letra1);
		int num2 = getNumIBAN(letra2);

		String isbanaux = num1 + "" + num2 + iban.substring(2);
		isbanaux = isbanaux.substring(6) + isbanaux.substring(0, 6);

		int resto = modulo97(isbanaux);
		return resto == 1;
	}

	private static int modulo97(String iban) {

		BigDecimal bd97 = new BigDecimal(97);
		int parts = (int) Math.ceil(iban.length() / 7.0);
		String remainder = "";

		for (int i = 1; i <= parts; i++) {
			int part = 0;
			if (iban.length() <= (((i - 1) * 7) + 7)) {
				part = iban.length();
			} else {
				part = i * 7;
			}
			remainder = String.valueOf(new BigDecimal(remainder + iban.substring((i - 1) * 7, part)).remainder(bd97));
		}

		return Integer.parseInt(remainder);
	}

	private static int getNumIBAN(char letra) {
		String letras = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		return letras.indexOf(letra) + 10;
	}

	public static String formatearIBAN(String numCuentaValidar) {
		numCuentaValidar = numCuentaValidar.replaceAll("\\s", "");

		if (numCuentaValidar.length() == 20) {
			numCuentaValidar = calculoIban(numCuentaValidar) + numCuentaValidar;
		}

		if (validarDC(numCuentaValidar) && validarIban(numCuentaValidar)) {
			numCuentaValidar = numCuentaValidar.substring(0, 4) + " " + numCuentaValidar.substring(4, 8) + " "
					+ numCuentaValidar.substring(8, 12) + " " + numCuentaValidar.substring(12, 14) + " "
					+ numCuentaValidar.substring(14);
		}

		return numCuentaValidar;

	}

	private static String calculoIban(String numCuenta) {
		String countryCode = "ES";
		String countryNumber = "142800";
		String iban = "";
		String digitControl = "";

		String ccc = numCuenta + countryNumber;

		int digit = 98 - modulo(new BigDecimal(ccc), new BigDecimal(97));
		digitControl = digit < 10 ? "0" + digit : String.valueOf(digit);

		iban = countryCode + digitControl;
		return iban;
	}

	private static int modulo(BigDecimal dividend, BigDecimal divisor) {
		int partLength = 10;
		String divident = String.valueOf(dividend);

		while (divident.length() > partLength) {
			String part = divident.substring(0, partLength);
			divident = new BigDecimal(part).remainder(divisor).toString() + divident.substring(partLength);
		}

		return new BigDecimal(divident).remainder(divisor).intValue();
	}

}
