package danielcortes.xyz.controllers;

import danielcortes.xyz.data.DAOManager;
import danielcortes.xyz.informes.InformeEstadoResultado;
import danielcortes.xyz.models.estado_resultado.EstadoResultado;
import danielcortes.xyz.models.estado_resultado.EstadoResultadoDAO;
import danielcortes.xyz.models.tipo_egreso.TipoEgreso;
import danielcortes.xyz.utils.SaveFile;
import danielcortes.xyz.views.EstadoResultadoView;
import danielcortes.xyz.views.listeners.FocusLostListener;
import java.time.YearMonth;
import java.util.Optional;
import org.apache.poi.ss.usermodel.Workbook;

public class EstadoResultadoController extends BaseController {

  private EstadoResultadoView view;
  private EstadoResultado estadoResultado;
  private YearMonth mes;

  public EstadoResultadoController(EstadoResultadoView view) {
    this.view = view;
    this.setupViewEvents();
    this.updateMonth();
  }

  public void update() {
    this.updateMonth();
  }

  private void setupViewEvents() {
    this.view.getMonthCombo().addActionListener(e -> this.updateMonth());
    this.view.getYearSpinner().addChangeListener(e -> this.updateMonth());

    this.setupUpdateViewEvents();
    this.setupMovementViewEvents();

    this.view.getGuardarButton()
        .addActionListener(e -> EstadoResultadoController.this.guardarListener());
    this.view.getExportarButton()
        .addActionListener(e -> EstadoResultadoController.this.exportarListener());
  }

  private void setupUpdateViewEvents() {
    this.view.getGastosGeneralesCuentaCorrienteFactura().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateGastosGenerales());
    this.view.getGastosGeneralesCuentaCorrienteBoleta().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateGastosGenerales());
    this.view.getGastosGeneralesCuentaCorrienteSinRespaldo().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateGastosGenerales());

    this.view.getServiciosAgua().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateServicios());
    this.view.getServiciosLuz().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateServicios());
    this.view.getServiciosGas().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateServicios());
    this.view.getServiciosTelefono().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateServicios());
    this.view.getServiciosOtro().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateServicios());

    this.view.getGastosOperacionalesCostoVenta().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateGastosOperacionales());
    this.view.getGastosOperacionalesRemuneraciones().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateGastosOperacionales());
    this.view.getGastosOperacionalesFiniquitos().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateGastosOperacionales());
    this.view.getGastosOperacionalesAguinaldo().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateGastosOperacionales());
    this.view.getGastosOperacionalesBonos().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateGastosOperacionales());
    this.view.getGastosOperacionalesHonorariosContador().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateGastosOperacionales());
    this.view.getGastosOperacionalesArriendo().addFocusListener(
        (FocusLostListener) e -> EstadoResultadoController.this.updateGastosOperacionales());

    this.view.getResumenIVAFavor()
        .addFocusListener((FocusLostListener) e -> EstadoResultadoController.this.updateResumen());
    this.view.getResumenPPM()
        .addFocusListener((FocusLostListener) e -> EstadoResultadoController.this.updateResumen());
  }

  private void setupMovementViewEvents() {

    moveTo(this.view.getGastosOperacionalesCostoVenta(),
        this.view.getGastosOperacionalesRemuneraciones());
    moveTo(this.view.getGastosOperacionalesRemuneraciones(),
        this.view.getGastosOperacionalesFiniquitos());
    moveTo(this.view.getGastosOperacionalesFiniquitos(),
        this.view.getGastosOperacionalesAguinaldo());
    moveTo(this.view.getGastosOperacionalesAguinaldo(), this.view.getGastosOperacionalesBonos());
    moveTo(this.view.getGastosOperacionalesBonos(),
        this.view.getGastosOperacionalesHonorariosContador());
    moveTo(this.view.getGastosOperacionalesHonorariosContador(),
        this.view.getGastosOperacionalesArriendo());
    moveTo(this.view.getGastosOperacionalesArriendo(), this.view.getServiciosAgua());

    moveTo(this.view.getServiciosAgua(), this.view.getServiciosLuz());
    moveTo(this.view.getServiciosLuz(), this.view.getServiciosGas());
    moveTo(this.view.getServiciosGas(), this.view.getServiciosTelefono());
    moveTo(this.view.getServiciosTelefono(), this.view.getServiciosOtro());
    moveTo(this.view.getServiciosOtro(), this.view.getGastosGeneralesCuentaCorrienteFactura());

    moveTo(this.view.getGastosGeneralesCuentaCorrienteFactura(),
        this.view.getGastosGeneralesCuentaCorrienteBoleta());
    moveTo(this.view.getGastosGeneralesCuentaCorrienteBoleta(),
        this.view.getGastosGeneralesCuentaCorrienteSinRespaldo());
    moveTo(this.view.getGastosGeneralesCuentaCorrienteSinRespaldo(), this.view.getResumenPPM());

    moveTo(this.view.getResumenPPM(), this.view.getResumenIVAFavor());
  }

  private void guardarListener() {
    EstadoResultadoDAO dao = DAOManager.getEstadoResultadoDAO();
    dao.update(this.estadoResultado);
  }

  private void exportarListener() {
    Workbook wb = new InformeEstadoResultado(this.mes).generarInforme();
    SaveFile.saveToTempFileAndOpen(wb, "estado_resultado");
  }

  private void updateMonth() {
    this.mes = this.view.getMonth();
    Optional<EstadoResultado> optional = DAOManager.getEstadoResultadoDAO().getByMonth(this.mes);

    if (optional.isPresent()) {
      this.estadoResultado = optional.get();
    } else {
      this.estadoResultado = new EstadoResultado();
      this.estadoResultado.setMes(this.mes);
      DAOManager.getEstadoResultadoDAO().insert(estadoResultado);
    }

    this.fillVentas();
    this.fillGastosGenerales();
    this.fillServicios();
    this.fillGastosOperacionales();
    this.fillResumen();
  }

  private void fillVentas() {
    int ventaBruta = DAOManager.getIngresoDAO().getTotalIngresoMes(this.mes);
    int ventaExentas = DAOManager.getIngresoDAO().getTotalExentasMes(this.mes);
    int ventaNeta = (int) Math.round((double) ventaBruta / 1.19d);
    int ventaIVA = ventaBruta - ventaNeta;
    int ventaNetaYExentas = ventaExentas + ventaNeta;

    this.view.getVentaBrutaField().setValue(ventaBruta);
    this.view.getVentaIVAField().setValue(ventaIVA);
    this.view.getVentaNetaField().setValue(ventaNeta);
    this.view.getVentaExentasField().setValue(ventaExentas);
    this.view.getVentasNetaExentasField().setValue(ventaNetaYExentas);
  }

  private void fillGastosGenerales() {
    TipoEgreso facturaGastosGenerales = DAOManager.getTipoEgresoDAO()
        .getByNombre("Factura Gastos Generales").orElse(TipoEgreso.EMPTY);
    TipoEgreso gastoGeneralConBoleta = DAOManager.getTipoEgresoDAO()
        .getByNombre("Gasto General Con Boleta").orElse(TipoEgreso.EMPTY);
    TipoEgreso gastoGeneralSinRespaldo = DAOManager.getTipoEgresoDAO()
        .getByNombre("Gasto General Sin Respaldo").orElse(TipoEgreso.EMPTY);

    int cuentaCorrienteFactura = this.estadoResultado.getCuentaCorrienteFactura();
    int cuentaCorrienteBoleta = this.estadoResultado.getCuentaCorrienteBoleta();
    int cuentaCorrienteSinRespaldo = this.estadoResultado.getCuentaCorrienteSinRespaldo();
    int efectivoFacturaGastosGenerales = DAOManager.getEgresoDAO()
        .getTotalEgresoMesPorTipo(this.mes, facturaGastosGenerales);
    int efectivoGastoGeneralConBoleta = DAOManager.getEgresoDAO()
        .getTotalEgresoMesPorTipo(this.mes, gastoGeneralConBoleta);
    int efectivoGastoGeneralSinRespaldo = DAOManager.getEgresoDAO()
        .getTotalEgresoMesPorTipo(this.mes, gastoGeneralSinRespaldo);
    int gastoTotal = efectivoFacturaGastosGenerales + efectivoGastoGeneralConBoleta
        + efectivoGastoGeneralSinRespaldo + cuentaCorrienteBoleta + cuentaCorrienteFactura
        + cuentaCorrienteSinRespaldo;

    this.view.getGastosGeneralesEfectivoFacturaField().setValue(efectivoFacturaGastosGenerales);
    this.view.getGastosGeneralesEfectivoBoletaField().setValue(efectivoGastoGeneralConBoleta);
    this.view.getGastosGeneralesEfectivoSinRespaldo().setValue(efectivoGastoGeneralSinRespaldo);
    this.view.getGastosGeneralesCuentaCorrienteFactura().setValue(cuentaCorrienteFactura);
    this.view.getGastosGeneralesCuentaCorrienteBoleta().setValue(cuentaCorrienteBoleta);
    this.view.getGastosGeneralesCuentaCorrienteSinRespaldo().setValue(cuentaCorrienteSinRespaldo);
    this.view.getGastosGeneralesTotal().setValue(gastoTotal);
  }

  private void fillGastosOperacionales() {
    TipoEgreso tipoPagoPartime = DAOManager.getTipoEgresoDAO().getByNombre("Pago Partime").orElse(TipoEgreso.EMPTY);

    int costoVenta = this.estadoResultado.getCostoVenta();
    int remuneraciones = this.estadoResultado.getRemuneraciones();
    int finiquitos = this.estadoResultado.getFiniquitos();
    int aguinaldo = this.estadoResultado.getAguinaldo();
    int bonosPersonal = this.estadoResultado.getBonosPersonal();
    int honorariosContador = this.estadoResultado.getHonorariosContador();
    int arriendo = this.estadoResultado.getArriendo();
    int partime = DAOManager.getEgresoDAO().getTotalEgresoMesPorTipo(this.mes, tipoPagoPartime);
    int ventaBruta = DAOManager.getIngresoDAO().getTotalIngresoMes(this.mes);

    int total = costoVenta + remuneraciones + finiquitos + aguinaldo + bonosPersonal
        + honorariosContador + arriendo + partime;
    double porcentajeCostoVenta = (double) costoVenta / (double) ventaBruta * 100d;

    this.view.getGastosOperacionalesCostoVenta().setValue(costoVenta);
    this.view.getGastosOperacionesPorcentajeCostoVenta().setValue(porcentajeCostoVenta);
    this.view.getGastosOperacionalesRemuneraciones().setValue(remuneraciones);
    this.view.getGastosOperacionalesFiniquitos().setValue(finiquitos);
    this.view.getGastosOperacionalesAguinaldo().setValue(aguinaldo);
    this.view.getGastosOperacionalesBonos().setValue(bonosPersonal);
    this.view.getGastosOperacionalesHonorariosContador().setValue(honorariosContador);
    this.view.getGastosOperacionalesArriendo().setValue(arriendo);
    this.view.getGastosOperacionalesPartime().setValue(partime);

    this.view.getGastosOperacionalesTotal().setValue(total);
  }

  private void fillServicios() {
    int agua = this.estadoResultado.getAgua();
    int luz = this.estadoResultado.getLuz();
    int gas = this.estadoResultado.getGas();
    int telefono = this.estadoResultado.getTelefono();
    int otro = this.estadoResultado.getOtroServicio();

    int total = agua + luz + gas + telefono + otro;

    this.view.getServiciosAgua().setValue(agua);
    this.view.getServiciosLuz().setValue(luz);
    this.view.getServiciosGas().setValue(gas);
    this.view.getServiciosTelefono().setValue(telefono);
    this.view.getServiciosOtro().setValue(otro);
    this.view.getServiciosTotal().setValue(total);
  }

  private void fillResumen() {
    double ppm = this.estadoResultado.getPpm();
    int aFavor = this.estadoResultado.getIvaFavor();

    this.view.getResumenPPM().setValue(ppm);
    this.view.getResumenIVAFavor().setValue(aFavor);

    this.updateResumen();
  }

  private void updateGastosGenerales() {
    int oldCuentaCorrienteFactura = this.estadoResultado.getCuentaCorrienteFactura();
    int oldCuentaCorrienteBoleta = this.estadoResultado.getCuentaCorrienteBoleta();
    int oldCuentaCorrienteSinRespaldo = this.estadoResultado.getCuentaCorrienteSinRespaldo();
    int oldTotal = this.view.getGastosGeneralesTotal().getValue();

    int cuentaCorrienteFactura = this.view.getGastosGeneralesCuentaCorrienteFactura().getValue();
    int cuentaCorrienteBoleta = this.view.getGastosGeneralesCuentaCorrienteBoleta().getValue();
    int cuentaCorrienteSinRespaldo = this.view.getGastosGeneralesCuentaCorrienteSinRespaldo()
        .getValue();

    this.estadoResultado.setCuentaCorrienteFactura(cuentaCorrienteFactura);
    this.estadoResultado.setCuentaCorrienteBoleta(cuentaCorrienteBoleta);
    this.estadoResultado.setCuentaCorrienteSinRespaldo(cuentaCorrienteSinRespaldo);

    int total = oldTotal
        - (oldCuentaCorrienteFactura + oldCuentaCorrienteBoleta + oldCuentaCorrienteSinRespaldo)
        + (cuentaCorrienteFactura + cuentaCorrienteBoleta + cuentaCorrienteSinRespaldo);

    this.view.getGastosGeneralesTotal().setValue(total);

    this.updateResumen();
  }

  private void updateServicios() {
    int oldAgua = this.estadoResultado.getAgua();
    int oldLuz = this.estadoResultado.getLuz();
    int oldGas = this.estadoResultado.getGas();
    int oldTelefono = this.estadoResultado.getTelefono();
    int oldOtro = this.estadoResultado.getOtroServicio();
    int oldTotal = this.view.getServiciosTotal().getValue();

    int agua = this.view.getServiciosAgua().getValue();
    int luz = this.view.getServiciosLuz().getValue();
    int gas = this.view.getServiciosGas().getValue();
    int telefono = this.view.getServiciosTelefono().getValue();
    int otro = this.view.getServiciosOtro().getValue();

    this.estadoResultado.setAgua(agua);
    this.estadoResultado.setLuz(luz);
    this.estadoResultado.setGas(gas);
    this.estadoResultado.setTelefono(telefono);
    this.estadoResultado.setOtroServicio(otro);

    int total = oldTotal
        - (oldAgua + oldLuz + oldGas + oldTelefono + oldOtro)
        + (agua + luz + gas + telefono + otro);

    this.view.getServiciosTotal().setValue(total);

    this.updateResumen();
  }

  private void updateGastosOperacionales() {
    int oldCostoVenta = this.estadoResultado.getCostoVenta();
    int oldRemuneraciones = this.estadoResultado.getRemuneraciones();
    int oldFiniquitos = this.estadoResultado.getFiniquitos();
    int oldAguinaldo = this.estadoResultado.getAguinaldo();
    int oldBonos = this.estadoResultado.getBonosPersonal();
    int oldHonorarios = this.estadoResultado.getHonorariosContador();
    int oldArriendo = this.estadoResultado.getArriendo();
    int oldTotal = this.view.getGastosOperacionalesTotal().getValue();

    int costoVenta = this.view.getGastosOperacionalesCostoVenta().getValue();
    int remuneraciones = this.view.getGastosOperacionalesRemuneraciones().getValue();
    int finiquitos = this.view.getGastosOperacionalesFiniquitos().getValue();
    int aguinaldo = this.view.getGastosOperacionalesAguinaldo().getValue();
    int bonos = this.view.getGastosOperacionalesBonos().getValue();
    int honorarios = this.view.getGastosOperacionalesHonorariosContador().getValue();
    int arriendo = this.view.getGastosOperacionalesArriendo().getValue();

    int ventaBruta = DAOManager.getIngresoDAO().getTotalIngresoMes(this.mes);

    this.estadoResultado.setCostoVenta(costoVenta);
    this.estadoResultado.setRemuneraciones(remuneraciones);
    this.estadoResultado.setFiniquitos(finiquitos);
    this.estadoResultado.setAguinaldo(aguinaldo);
    this.estadoResultado.setBonosPersonal(bonos);
    this.estadoResultado.setHonorariosContador(honorarios);
    this.estadoResultado.setArriendo(arriendo);

    int total = oldTotal
        - (oldCostoVenta + oldRemuneraciones + oldFiniquitos + oldAguinaldo + oldBonos
        + oldHonorarios + oldArriendo)
        + (costoVenta + remuneraciones + finiquitos + aguinaldo + bonos + honorarios + arriendo);
    double porcentajeCostoVenta = (double) costoVenta / (double) ventaBruta * 100d;

    this.view.getGastosOperacionalesTotal().setValue(total);
    this.view.getGastosOperacionesPorcentajeCostoVenta().setValue(porcentajeCostoVenta);

    this.updateResumen();
  }

  private void updateResumen() {
    int bruto = this.view.getVentaBrutaField().getValue();
    int totalGastosOperacionales = this.view.getGastosOperacionalesTotal().getValue();
    int totalGastosGenerales = this.view.getGastosGeneralesTotal().getValue();
    int totalServicios = this.view.getServiciosTotal().getValue();
    int netoExentas = this.view.getVentasNetaExentasField().getValue();
    int iva = this.view.getVentaIVAField().getValue();
    double ppm = this.view.getResumenPPM().getValue();
    int ivaFavor = this.view.getResumenIVAFavor().getValue();

    int utilidad = bruto - totalGastosGenerales - totalGastosOperacionales - totalServicios;
    int ppmMes = (int) Math.round(ppm * (double) netoExentas / 100d);
    int IVAPPM = iva + ppmMes;
    int aPagar = IVAPPM - ivaFavor;
    int resultado = utilidad - aPagar;

    this.view.getResumenUtilidad().setValue(utilidad);
    this.view.getResumenPPMMes().setValue(ppmMes);
    this.view.getResumenIVAMes().setValue(iva);
    this.view.getResumenIVAPPM().setValue(IVAPPM);
    this.view.getResumenAPagar().setValue(aPagar);
    this.view.getResumenResultado().setValue(resultado);

    this.estadoResultado.setPpm(ppm);
    this.estadoResultado.setIvaFavor(ivaFavor);
  }

}

