"use strict";

import {
  mostrarMensajes,
  mostrarToastify,
  obtenerNombreUsuario,
  obtenerHTMLBotonesDropdown,
} from "../../../../assets/js/app/funcionesGenerales.js?v=2.0.0";
import TipoPlanilla from "../models/tipoPlanillaModel.js?v=2.0.0";
import UnidadTrabajo from "../models/unidadTrabajoModel.js?v=2.0.0";
import CustomDataTable from "../../../../assets/js/app/CustomDataTable.js?v=2.0.0";
import metodosFormularios from "../../../../assets/js/app/metodosFormularios.js?v=2.0.0";
import Empleado from "../models/empleadoModel.js?v=2.0.0";
import Bono from "../models/bonoModel.js?v=2.0.0";

const loader = document.querySelector(".loader");

!(function () {
  document
    .getElementById("cbo-tipoPlanilla")
    .addEventListener("change", function () {
      configuracion.evaluarTipoPlanilla();
    });

  document.getElementById("btn-agregar").addEventListener("click", function () {
    evaluarPestaña();
  });

  document
    .getElementById("cbo-tipoAsignacion")
    .addEventListener("change", function () {
      configAsignacion.evaluarTipoAsignacion();
    });

  document
    .getElementById("cbo-departamento")
    .addEventListener("change", function () {
      configAsignacion.evaluarDepartamento();
    });

  document.getElementById("cbo-puesto").addEventListener("change", function () {
    configAsignacion.evaluarPuesto();
  });

  document
    .getElementById("num-montoPeriodico")
    .addEventListener("blur", function () {
      let monto = this.value;

      if (monto) {
        this.value = parseFloat(monto).toFixed(2);
      }
    });

  document
    .getElementById("cbo-periodicidad")
    .addEventListener("change", function () {
      configPeriodicos.evaluarPeriodicidad();
    });

  document
    .getElementById("ubicacion-form")
    .addEventListener("submit", function (e) {
      e.preventDefault();
      configuracion.buscar();
    });

  document
    .getElementById("asignacion-form")
    .addEventListener("submit", function (e) {
      e.preventDefault();
      configAsignacion.guardar();
    });

  document
    .getElementById("bonoPeriodico-form")
    .addEventListener("submit", function (e) {
      e.preventDefault();
      configPeriodicos.guardar();
    });

  document
    .getElementById("bonoExtraordinario-form")
    .addEventListener("submit", function (e) {
      e.preventDefault();
      configExtraordinarios.guardar();
    });

  document.addEventListener("click", function (e) {
    const target = e.target;

    if (target.classList.contains("eliminar-detallePeriodico"))
      configDetallePeriodico.eliminar(target.dataset.id);

    if (target.classList.contains("editar-bonoPeriodico"))
      configPeriodicos.editar(target.dataset.id);

    if (target.classList.contains("eliminar-bonoPeriodico"))
      configPeriodicos.eliminar(target.dataset.id);

    if (target.classList.contains("editar-bonoExtraordinario"))
      configExtraordinarios.editar(target.dataset.id);

    if (target.classList.contains("eliminar-bonoExtraordinario"))
      configExtraordinarios.eliminar(target.dataset.id);

    if (target.classList.contains("eliminar-detalleExtraordinario"))
      configDetalleExtraordinario.eliminar(target.dataset.id);
  });
})();

window.onload = async () => {
  try {
    await inicializarTablas();
    await configuracion.inicializar();
    loader && loader.classList.add("d-none");
  } catch (err) {
    mostrarMensajes.error(err);
  }
};

function inicializarTablas() {
  return new Promise((resolve, reject) => {
    try {
      configPeriodicos.tabla = new CustomDataTable({
        id: "bonosPeriodicos-tbl",
        alineadoIzquierda: [1],
        noOrdenable: [9],
      });

      configExtraordinarios.tabla = new CustomDataTable({
        id: "bonosUnicos-tbl",
        alineadoIzquierda: [1],
        noOrdenable: [8],
      });

      configDetallePeriodico.tabla = new CustomDataTable({
        id: "detallePeriodico-tbl",
        alineadoIzquierda: [2, 3, 4],
        noOrdenable: [7],
        adicional: {
          lengthChange: false,
          buttons: [
            {
              text: '<i class="fas fa-plus"></i> Agregar',
              className: "btn-primary btn-sm",

              action: function (e, dt, node, config) {
                configDetallePeriodico.editar();
              },
            },
          ],
        },
      });

      configDetallePeriodico.tabla.tabla
        .buttons()
        .container()
        .appendTo("#detallePeriodico-tbl_wrapper .col-md-6:eq(0)");

      configDetalleExtraordinario.tabla = new CustomDataTable({
        id: "detalleExtraordinario-tbl",
        alineadoIzquierda: [2, 3, 4],
        noOrdenable: [7],
        adicional: {
          lengthChange: false,
          buttons: [
            {
              text: '<i class="fas fa-plus"></i> Agregar',
              className: "btn-primary btn-sm",
              action: function (e, dt, node, config) {
                configDetalleExtraordinario.editar();
              },
            },
          ],
        },
      });

      configDetalleExtraordinario.tabla.tabla
        .buttons()
        .container()
        .appendTo("#detalleExtraordinario-tbl_wrapper .col-md-6:eq(0)");

      resolve();
    } catch (err) {
      reject(err);
    }
  });
}

function evaluarPestaña() {
  let pestaniaActiva = document.querySelector(
    "#pestaniasPrincipales .nav-link.active"
  ).id;

  switch (pestaniaActiva) {
    case "periodicos-tab":
      configPeriodicos.editar();
      break;
    case "unicos-tab":
      configExtraordinarios.editar();
      break;
  }
}

const configuracion = {
  catalogos: {
    tiposPlanilla: [],
    unidades: [],
    empleados: [],
  },
  campos: {
    tipoPlanilla: document.querySelector("#cbo-tipoPlanilla"),
    empresa: document.querySelector("#cbo-empresa"),
    sucursal: document.querySelector("#cbo-sucursal"),
    proyecto: document.querySelector("#cbo-proyecto"),
    unidadTrabajo: document.querySelector("#cbo-unidadTrabajo"),
  },
  ubicacion: null,
  inicializar: function () {
    return new Promise(async (resolve, reject) => {
      try {
        const { data: tiposPlanilla } = await TipoPlanilla.obtenerPorUsuario();

        this.catalogos.tiposPlanilla = tiposPlanilla;
        let opciones = tiposPlanilla.map(
          (tipo) =>
            `<option value="${tipo.codtipoplanilla}">${tipo.tipoPlanilla}</option>`
        );

        opciones.length > 0
          ? opciones.unshift(
              '<option value="" selected disabled>Seleccione un tipo de planilla</option>'
            )
          : opciones.unshift(
              '<option value="" selected disabled>No hay tipos de planilla disponibles</option>'
            );

        this.campos.tipoPlanilla.innerHTML = opciones.join("");

        $(`#${this.campos.tipoPlanilla.id}`)
          .selectpicker("destroy")
          .selectpicker();

        const { data: unidades } = await UnidadTrabajo.obtenerTodos();

        this.catalogos.unidades = unidades;

        resolve();
      } catch (err) {
        reject(err);
      }
    });
  },
  evaluarTipoPlanilla: async function () {
    const tipoPlanilla = this.campos.tipoPlanilla.value;

    document.getElementById("btn-agregar").disabled = !tipoPlanilla;

    if (tipoPlanilla) {
      const { data: empleados = [] } = await Empleado.obtenerPorTipoPlanilla({
        codtipoplanilla: tipoPlanilla,
      });

      await configAsignacion.inicializar({
        unidadesTrabajo: this.catalogos.unidades,
        empleados,
      });
    }
  },
  buscar: async function () {
    try {
      const codtipoplanilla = this.campos.tipoPlanilla.value;

      if (!codtipoplanilla) return;

      const { data: bonos = [] } = await Bono.obtenerPorTipoPlanilla({
        codtipoplanilla: this.campos.tipoPlanilla.value,
      });

      let bonosPeriodicos = bonos.filter(
          (bono) => parseInt(bono.idTipo) === 1 && bono.pagado == 0
        ),
        bonosUnicos = bonos.filter((bono) => parseInt(bono.idTipo) === 2);

      await configPeriodicos.configurar({ bonos: bonosPeriodicos });
      await configExtraordinarios.configurar({ bonos: bonosUnicos });
    } catch (err) {
      mostrarMensajes.error(err);
    }
  },
  obtenerTipoPlanilla: function () {
    return this.campos.tipoPlanilla.value;
  },
};

const configPeriodicos = {
  id: 0,
  cnt: 0,
  data: {},
  tabla: null,
  form: `bonoPeriodico-form`,
  modal: {
    id: `modal-bonoPeriodico`,
    mostrar: () => $(`#${configPeriodicos.modal.id}`).modal(`show`),
    ocultar: () => $(`#${configPeriodicos.modal.id}`).modal(`hide`),
  },
  campos: {
    descripcion: document.getElementById("txt-descripcionPeriodico"),
    periodicidad: document.getElementById("cbo-periodicidad"),
    notas: document.getElementById("txt-notasPeriodico"),
    monto: document.getElementById("num-montoPeriodico"),
  },
  configurar: function ({ bonos }) {
    return new Promise(async (resolve, reject) => {
      try {
        await this.limpiar();

        bonos.forEach((bono) => {
          this.cnt++;
          this.data[this.cnt] = bono;

          const fila = this.prepararParaFila({ datos: bono, id: this.cnt });

          this.tabla.agregarFila({
            datos: fila,
            idFila: `trBonoPeriodico${this.cnt}`,
          });
        });

        this.tabla.redibujar();

        resolve();
      } catch (err) {
        reject(err);
      }
    });
  },
  editar: async function (id = 0) {
    await metodosFormularios.limpiar({ id: this.form });

    try {
      this.id = id;

      let detalles = [];

      if (this.id > 0) {
        const bono = new Bono(this.data[this.id]);

        this.campos.descripcion.value = bono.descripcion;
        this.campos.periodicidad.value = bono.idPeriodicidad;
        this.campos.monto.value = bono.monto;

        const { data: tmp = [] } = await bono.obtenerDetalles();

        detalles = tmp;
      }

      this.evaluarPeriodicidad();

      await configDetallePeriodico.configurar({ detalles });

      this.modal.mostrar();
    } catch (err) {
      mostrarMensajes.error(err);
    }
  },
  guardar: async function () {
    if (!metodosFormularios.validar({ id: this.form })) return;

    try {
      const detalles = configDetallePeriodico.obtenerDatos();

      if (detalles.length == 0) {
        const confirmacion = await mostrarMensajes.confirm({
          message: `Está a punto de guardar un bono sin asignaciones, ¿Desea continuar?`,
        });

        if (!confirmacion) return;
      }

      const empleados =
        configAsignacion.calcularCantidadEmpleados({ detalles }) || 0;

      let bono = new Bono({
        id: this.data[this.id]?.id || 0,
        codtipoplanilla: configuracion.obtenerTipoPlanilla() || 0,
        idTipo: 1,
        tipo: "Periodico",
        descripcion: this.campos.descripcion.value,
        idPeriodicidad: this.campos.periodicidad.value,
        empleados,
        periodicidad:
          this.campos.periodicidad.options[
            this.campos.periodicidad.selectedIndex
          ].text,
        monto: this.campos.monto.value,
        detalles,
        usuario: obtenerNombreUsuario(),
        fechaRegistro:
          this.data[this.id]?.fechaRegistro ||
          moment().format("DD-MM-YYYY HH:mm"),
        fechaModificacion:
          this.id > 0 ? moment().format("DD-MM-YYYY HH:mm") : "Sin registros",
        ultimaAplicacion:
          this.data[this.id]?.ultimaAplicacion || "Sin registros",
      });

      const respuesta = await bono.guardar();

      switch (respuesta.message) {
        case "success":
          bono.id = respuesta.data.id;

          const fila = this.prepararParaFila({
            datos: bono,
            id: this.id > 0 ? this.id : this.cnt + 1,
          });

          if (this.id == 0) {
            this.cnt++;
            this.id = this.cnt;

            this.tabla
              .agregarFila({ datos: fila, idFila: `trBonoPeriodico${this.id}` })
              .redibujar();
          } else {
            this.tabla
              .actualizarFila({
                datos: fila,
                idFila: `trBonoPeriodico${this.id}`,
              })
              .redibujar();
          }

          this.data[this.id] = bono;

          mostrarToastify({
            type: "success",
            message: `Se ha guardado el bono de forma exitosa.`,
          });

          this.modal.ocultar();
          break;
        default:
          mostrarMensajes.error(respuesta);
          break;
      }
    } catch (err) {
      mostrarMensajes.error(err);
    }
  },
  eliminar: async function (id = 0) {
    const bono = new Bono(this.data[id]);

    try {
      const confirmacion = await mostrarMensajes.confirm({
        message: `¿Está seguro que desea eliminar el bono ${bono.descripcion}?`,
      });

      if (!confirmacion) return;

      const respuesta = await bono.eliminar();

      switch (respuesta.message) {
        case "success":
          this.tabla
            .eliminarFila({ idFila: `trBonoPeriodico${id}` })
            .redibujar();
          delete this.data[id];

          mostrarToastify({
            type: "success",
            message: `Se ha eliminado el bono de forma exitosa.`,
          });
          break;
        default:
          mostrarMensajes.error(respuesta);
          break;
      }
    } catch (err) {
      if (!!err) mostrarMensajes.error(err);
    }
  },
  prepararParaFila: function ({ datos, id }) {
    return {
      0: id,
      1: datos.descripcion,
      2: datos.periodicidad,
      3: `$${parseFloat(datos.monto).toFixed(2)}`,
      4: datos.empleados || 0,
      5: datos.fechaRegistro,
      6: datos.fechaModificacion,
      7: datos.ultimaAplicacion,
      8: datos.usuario,
      9: obtenerHTMLBotonesDropdown([
        {
          tipo: "edit",
          texto: "Editar",
          selectorClase: "editar-bonoPeriodico",
          selectorId: id,
        },
        {
          tipo: "delete",
          texto: "Eliminar",
          selectorClase: "eliminar-bonoPeriodico",
          selectorId: id,
        },
      ]),
    };
  },
  evaluarPeriodicidad: function () {
    const periodicidad = this.campos.periodicidad.value;
    let mensaje = "Seleccione una periodicidad";

    if (periodicidad) {
      switch (parseInt(periodicidad)) {
        case 1:
          mensaje = "Se pagará en cada planilla generada de forma quincenal;";
          break;
        case 2:
          mensaje = "Se pagará en la segunda planilla generada de cada mes;";
          break;
      }
    }

    this.campos.notas.value = mensaje;
  },
  limpiar: function () {
    return new Promise((resolve) => {
      this.id = 0;
      this.cnt = 0;
      this.data = {};
      this.tabla.limpiar().redibujar();
      resolve();
    });
  },
};

const configExtraordinarios = {
  id: 0,
  cnt: 0,
  data: {},
  tabla: null,
  form: `bonoExtraordinario-form`,
  modal: {
    id: "modal-bonoExtraordinario",
    mostrar: () => $(`#${configExtraordinarios.modal.id}`).modal(`show`),
    ocultar: () => $(`#${configExtraordinarios.modal.id}`).modal(`hide`),
  },
  campos: {
    descripcion: document.getElementById("txt-descripcionExtraordinario"),
    mesPago: document.getElementById("txt-mesPagoExtraordinario"),
    planillaPago: document.getElementById("cbo-quincenaExtraordinario"),
    monto: document.getElementById("num-montoExtraordinario"),
  },
  configurar: function ({ bonos }) {
    return new Promise(async (resolve, reject) => {
      try {
        await this.limpiar();

        bonos.forEach((bono) => {
          this.cnt++;
          this.data[this.cnt] = bono;

          const fila = this.prepararParaFila({ datos: bono, id: this.cnt });

          this.tabla.agregarFila({
            datos: fila,
            idFila: `trBonoExtraordinario${this.cnt}`,
          });
        });

        this.tabla.redibujar();

        resolve();
      } catch (err) {
        reject(err);
      }
    });
  },
  editar: async function (id = 0) {
    await metodosFormularios.limpiar({ id: this.form });

    try {
      this.id = id;

      let detalles = [];

      if (this.id > 0) {
        const bono = new Bono(this.data[this.id]);

        this.campos.descripcion.value = bono.descripcion;
        this.campos.mesPago._flatpickr.setDate(
          moment(bono.fechaPago, "DD-MM-YYYY").toDate()
        );
        this.campos.planillaPago.value = bono.planillaPago;
        this.campos.monto.value = bono.monto;

        const { data: tmp = [] } = await bono.obtenerDetalles();

        detalles = tmp;
      }

      await configDetalleExtraordinario.configurar({ detalles });

      this.modal.mostrar();
    } catch (err) {
      mostrarMensajes.error(err);
    }
  },
  guardar: async function () {
    if (!metodosFormularios.validar({ id: this.form })) return;

    try {
      const detalles = configDetalleExtraordinario.obtenerDatos();

      if (detalles.length == 0) {
        const confirmacion = await mostrarMensajes.confirm({
          message: `Está a punto de guardar un bono sin asignaciones, ¿Desea continuar?`,
        });

        if (!confirmacion) return;
      }

      const empleados =
        configAsignacion.calcularCantidadEmpleados({ detalles }) || 0;

      let mesPago = this.campos.mesPago._flatpickr.selectedDates[0],
        planillaPago = this.campos.planillaPago.value,
        fechaPago = null;

      if (!!mesPago) {
        let tmp = moment(mesPago);

        fechaPago =
          planillaPago == 1
            ? tmp.startOf("month").format("DD-MM-YYYY")
            : tmp.endOf("month").format("DD-MM-YYYY");
        mesPago = moment(mesPago).format("MM-YYYY");
      }

      const bono = new Bono({
        id: this.data[this.id]?.id || 0,
        codtipoplanilla: configuracion.obtenerTipoPlanilla() || 0,
        idTipo: 2,
        tipo: "Extraordinario",
        empleados,
        descripcion: this.campos.descripcion.value,
        mesPago,
        planillaPago,
        fechaPago,
        monto: this.campos.monto.value,
        detalles,
        usuario: obtenerNombreUsuario(),
        fechaRegistro:
          this.data[this.id]?.fechaRegistro ||
          moment().format("DD-MM-YYYY HH:mm"),
        fechaModificacion:
          this.id > 0 ? moment().format("DD-MM-YYYY HH:mm") : "Sin registros",
      });

      const respuesta = await bono.guardar();

      switch (respuesta.message) {
        case "success":
          bono.id = respuesta.data.id;

          const fila = this.prepararParaFila({
            datos: bono,
            id: this.id > 0 ? this.id : this.cnt + 1,
          });

          if (this.id == 0) {
            this.cnt++;
            this.id = this.cnt;

            this.tabla
              .agregarFila({
                datos: fila,
                idFila: `trBonoExtraordinario${this.id}`,
              })
              .redibujar();
          } else {
            this.tabla
              .actualizarFila({
                datos: fila,
                idFila: `trBonoExtraordinario${this.id}`,
              })
              .redibujar();
          }

          this.data[this.id] = bono;

          mostrarToastify({
            type: "success",
            message: `Se ha guardado el bono de forma exitosa.`,
          });

          this.modal.ocultar();
          break;
        default:
          mostrarMensajes.error(respuesta);
          break;
      }
    } catch (err) {
      mostrarMensajes.error(err);
    }
  },
  eliminar: async function (id) {
    const bono = new Bono(this.data[id]);

    try {
      const confirmacion = await mostrarMensajes.confirm({
        message: `¿Está seguro que desea eliminar el bono ${bono.descripcion}?`,
      });

      if (!confirmacion) return;

      const respuesta = await bono.eliminar();

      switch (respuesta.message) {
        case "success":
          this.tabla
            .eliminarFila({ idFila: `trBonoExtraordinario${id}` })
            .redibujar();
          delete this.data[id];

          mostrarToastify({
            type: "success",
            message: `Se ha eliminado el bono de forma exitosa.`,
          });
          break;
        default:
          mostrarMensajes.error(respuesta);
          break;
      }
    } catch (err) {
      if (!!err) mostrarMensajes.error(err);
    }
  },
  prepararParaFila: function ({ datos, id }) {
    let claseBadge = "bg-success";
    let momentFechaPago = moment(datos.fechaPago, "DD-MM-YYYY");

    let dias = momentFechaPago.diff(moment().toDate(), "days");

    if (dias <= 3) {
      claseBadge = "bg-warning";
    }

    if (dias <= 0) {
      claseBadge = "bg-danger";
    }

    return {
      0: id,
      1: datos.descripcion,
      2: `<span class="badge ${claseBadge}">${datos.fechaPago}</span>`,
      3: `$${parseFloat(datos.monto).toFixed(2)}`,
      4: datos.empleados || 0,
      5: datos.fechaRegistro,
      6: datos.fechaModificacion,
      7: datos.usuario,
      8: obtenerHTMLBotonesDropdown([
        {
          tipo: "edit",
          texto: "Editar",
          selectorClase: "editar-bonoExtraordinario",
          selectorId: id,
        },
        {
          tipo: "delete",
          texto: "Eliminar",
          selectorClase: "eliminar-bonoExtraordinario",
          selectorId: id,
        },
      ]),
    };
  },
  limpiar: function () {
    return new Promise((resolve) => {
      this.id = 0;
      this.cnt = 0;
      this.data = {};
      this.tabla.limpiar().redibujar();
      resolve();
    });
  },
};

const configDetallePeriodico = {
  id: 0,
  cnt: 0,
  data: {},
  tabla: null,
  configurar: function ({ detalles }) {
    return new Promise(async (resolve, reject) => {
      try {
        await this.limpiar();

        detalles.forEach((detalle) => {
          this.cnt++;
          this.data[this.cnt] = detalle;

          const fila = this.prepararParaFila({ datos: detalle, id: this.cnt });

          this.tabla.agregarFila({
            datos: fila,
            idFila: `trDetallePeriodico${this.cnt}`,
          });
        });

        this.tabla.redibujar();
        resolve();
      } catch (err) {
        reject(err);
      }
    });
  },
  editar: function (id = 0) {
    this.id = id;
    configAsignacion.editar(id, this.guardar.bind(this));
  },
  guardar: function ({ data }) {
    let fila = this.prepararParaFila({
      datos: data,
      id: this.id > 0 ? this.id : this.cnt + 1,
    });

    if (this.id == 0) {
      this.cnt++;
      this.id = this.cnt;

      this.tabla
        .agregarFila({ datos: fila, idFila: `trDetallePeriodico${this.id}` })
        .redibujar();
    } else {
      this.tabla
        .actualizarFila({ datos: fila, idFila: `trDetallePeriodico${this.id}` })
        .redibujar();
    }

    this.data[this.id] = data;
  },
  prepararParaFila: function ({ datos, id }) {
    return {
      0: id,
      1: datos.tipoAsignacion,
      2: datos.asignacion,
      3: datos.nombreDepartamento,
      4: datos.nombrePuesto,
      5: datos.fechaRegistro,
      6: datos.usuario,
      7: obtenerHTMLBotonesDropdown([
        {
          tipo: "delete",
          texto: "Eliminar",
          selectorClase: "eliminar-detallePeriodico",
          selectorId: id,
        },
      ]),
    };
  },
  eliminar: async function (id = 0) {
    let detalle = this.data[id];

    try {
      const confirmacion = await mostrarMensajes.confirm({
        message: `Se eliminará el detalle de forma permanente. ¿Desea continuar?`,
      });

      if (!confirmacion) return;

      delete this.data[id];
      this.tabla
        .eliminarFila({ idFila: `trDetallePeriodico${id}` })
        .redibujar();

      mostrarToastify({
        type: "success",
        message: `Se ha eliminado el detalle de forma permanente.`,
      });
    } catch (err) {
      if (!!err) mostrarMensajes.error(err);
    }
  },
  limpiar: function () {
    return new Promise((resolve) => {
      this.cnt = 0;
      this.id = 0;
      this.data = {};
      this.tabla.limpiar().redibujar();
      resolve();
    });
  },
  obtenerDatos: function () {
    return [...Object.values(this.data)];
  },
};

const configDetalleExtraordinario = {
  id: 0,
  cnt: 0,
  data: {},
  tabla: null,
  configurar: function ({ detalles }) {
    return new Promise(async (resolve, reject) => {
      try {
        await this.limpiar();

        detalles.forEach((detalle) => {
          this.cnt++;
          this.data[this.cnt] = detalle;

          const fila = this.prepararParaFila({ datos: detalle, id: this.cnt });

          this.tabla.agregarFila({
            datos: fila,
            idFila: `trDetalleExtraordinario${this.cnt}`,
          });
        });

        this.tabla.redibujar();

        resolve();
      } catch (err) {
        reject(err);
      }
    });
  },
  editar: function (id = 0) {
    this.id = id;
    configAsignacion.editar(id, this.guardar.bind(this));
  },
  guardar: function ({ data }) {
    let fila = this.prepararParaFila({
      datos: data,
      id: this.id > 0 ? this.id : this.cnt + 1,
    });

    if (this.id == 0) {
      this.cnt++;
      this.id = this.cnt;

      this.tabla
        .agregarFila({
          datos: fila,
          idFila: `trDetalleExtraordinario${this.id}`,
        })
        .redibujar();
    } else {
      this.tabla
        .actualizarFila({
          datos: fila,
          idFila: `trDetalleExtraordinario${this.id}`,
        })
        .redibujar();
    }

    this.data[this.id] = data;
  },
  prepararParaFila: function ({ datos, id }) {
    return {
      0: id,
      1: datos.tipoAsignacion,
      2: datos.asignacion,
      3: datos.nombreDepartamento,
      4: datos.nombrePuesto,
      5: datos.fechaRegistro,
      6: datos.usuario,
      7: obtenerHTMLBotonesDropdown([
        {
          tipo: "delete",
          texto: "Eliminar",
          selectorClase: "eliminar-detalleExtraordinario",
          selectorId: id,
        },
      ]),
    };
  },
  eliminar: async function (id = 0) {
    try {
      const confirmacion = await mostrarMensajes.confirm({
        message: `Se eliminará el detalle de forma permanente. ¿Desea continuar?`,
      });

      if (!confirmacion) return;

      delete this.data[id];
      this.tabla
        .eliminarFila({ idFila: `trDetalleExtraordinario${id}` })
        .redibujar();

      mostrarToastify({
        type: "success",
        message: `Se ha eliminado el detalle de forma permanente.`,
      });
    } catch (err) {
      if (!!err) mostrarMensajes.error(err);
    }
  },
  limpiar: function () {
    return new Promise((resolve) => {
      this.cnt = 0;
      this.id = 0;
      this.data = {};
      this.tabla.limpiar().redibujar();
      resolve();
    });
  },
  obtenerDatos: function () {
    return [...Object.values(this.data)];
  },
};

const configAsignacion = {
  id: 0,
  data: {},
  callback: null,
  empleados: [],
  inicializar: function ({ unidadesTrabajo, empleados = [] }) {
    return new Promise((resolve, reject) => {
      try {
        let opciones = unidadesTrabajo.map(
          (unidad) =>
            `<option value="${unidad.id}">${unidad.unidadTrabajo}</option>`
        );

        opciones.length > 0
          ? opciones.unshift(
              '<option value="" selected disabled>Seleccione una unidad de trabajo</option>'
            )
          : opciones.unshift(
              '<option value="" selected disabled>No hay unidades de trabajo disponibles</option>'
            );

        this.campos.unidadTrabajo.innerHTML = opciones.join("");

        $(`#${this.campos.unidadTrabajo.id}`)
          .selectpicker("destroy")
          .selectpicker();

        this.empleados = empleados;

        let coddepartamentos = [
            ...new Set(empleados.map((emp) => parseInt(emp.coddepartamento))),
          ],
          departamentos = [];

        if (coddepartamentos.length > 0) {
          departamentos = coddepartamentos.map((cod) => {
            const { nombreDepartamento } = empleados.find(
              (emp) => parseInt(emp.coddepartamento) === cod
            );

            return { coddepartamento: cod, nombreDepartamento };
          });
        }

        opciones = departamentos.map(
          (departamento) =>
            `<option value="${departamento.coddepartamento}">${departamento.nombreDepartamento}</option>`
        );

        opciones.length > 1 &&
          opciones.unshift(
            `<option value="0">Todos los departamentos</option>`
          );

        opciones.length > 0
          ? opciones.unshift(
              '<option value="" selected disabled>Seleccione</option>'
            )
          : opciones.unshift(
              '<option value="" selected disabled>No hay departamentos disponibles</option>'
            );

        this.campos.departamento.innerHTML = opciones.join("");

        $(`#${this.campos.departamento.id}`)
          .selectpicker("destroy")
          .selectpicker();

        resolve();
      } catch (err) {
        reject(err);
      }
    });
  },
  form: `asignacion-form`,
  modal: {
    id: `modal-asignacion`,
    mostrar: () => $(`#${configAsignacion.modal.id}`).modal(`show`),
    ocultar: () => $(`#${configAsignacion.modal.id}`).modal(`hide`),
  },
  campos: {
    tipoAsignacion: document.getElementById("cbo-tipoAsignacion"),
    unidadTrabajo: document.getElementById("cbo-unidad"),
    departamento: document.getElementById("cbo-departamento"),
    puesto: document.getElementById("cbo-puesto"),
    empleado: document.getElementById("cbo-empleado"),
  },
  editar: async function (id = 0, callback) {
    await metodosFormularios.limpiar({ id: this.form });

    try {
      this.id = id;
      this.callback = callback;

      if (this.id > 0) {
      }

      this.evaluarTipoAsignacion();

      this.modal.mostrar();
    } catch (err) {
      mostrarMensajes.error(err);
    }
  },
  guardar: function () {
    if (!metodosFormularios.validar({ id: this.form })) return;

    const tipoAsignacion = this.campos.tipoAsignacion.value;

    let data = {
      id: 0,
      idTipoAsignacion: tipoAsignacion,
      tipoAsignacion:
        this.campos.tipoAsignacion.options[
          this.campos.tipoAsignacion.selectedIndex
        ].text,
      idAsignacion:
        tipoAsignacion == 1
          ? this.campos.unidadTrabajo.value
          : tipoAsignacion == 2
          ? this.campos.empleado.value
          : this.campos.puesto.value,
      asignacion:
        tipoAsignacion == 1
          ? this.campos.unidadTrabajo.options[
              this.campos.unidadTrabajo.selectedIndex
            ].text
          : tipoAsignacion == 2
          ? this.campos.empleado.options[this.campos.empleado.selectedIndex]
              .text
          : this.campos.puesto.options[this.campos.puesto.selectedIndex].text,
      nombreDepartamento:
        tipoAsignacion == 2
          ? this.campos.departamento.options[
              this.campos.departamento.selectedIndex
            ].text
          : "N/A",
      nombrePuesto:
        tipoAsignacion == 2
          ? this.campos.puesto.options[this.campos.puesto.selectedIndex].text
          : "N/A",
      fechaRegistro: moment().format("DD-MM-YYYY"),
      usuario: obtenerNombreUsuario(),
    };

    this.modal.ocultar();
    this.callback({ data });
  },
  evaluarTipoAsignacion: function () {
    const tipoAsignacion = this.campos.tipoAsignacion.value;
    const contenedorUnidades = document.getElementById("contenedor-unidades"),
      contenedorEmpleado = document.getElementById("contenedor-empleado"),
      camposUnidades = contenedorUnidades.querySelectorAll("select"),
      camposEmpleado = contenedorEmpleado.querySelectorAll("select");

    if (!tipoAsignacion) {
      contenedorUnidades.classList.add("d-none");
      contenedorEmpleado.classList.add("d-none");
      camposUnidades.forEach((campo) => (campo.required = false));
      return;
    }

    if (parseInt(tipoAsignacion) === 1) {
      contenedorUnidades.classList.remove("d-none");
      contenedorEmpleado.classList.add("d-none");
      camposUnidades.forEach((campo) => (campo.required = true));
      camposEmpleado.forEach((campo) => (campo.required = false));
    }

    if (parseInt(tipoAsignacion) === 2 || parseInt(tipoAsignacion) === 3) {
      const contenedorCboEmpleado = document.getElementById(
        "contenedor-cboEmpleado"
      );
      contenedorUnidades.classList.add("d-none");
      contenedorEmpleado.classList.remove("d-none");
      camposUnidades.forEach((campo) => (campo.required = false));
      camposEmpleado.forEach((campo) => (campo.required = true));
      this.campos.empleado.required = parseInt(tipoAsignacion) == 2;
      this.evaluarDepartamento();

      parseInt(tipoAsignacion) == 2
        ? contenedorCboEmpleado.classList.remove("d-none")
        : contenedorCboEmpleado.classList.add("d-none");
    }
  },
  evaluarDepartamento: function () {
    const coddepartamento = this.campos.departamento.value;

    let opciones = [
      `<option value="" selected disabled>Seleccione un departamento</option>`,
    ];

    if (coddepartamento) {
      let codpuestos = [
          ...new Set(this.empleados.map((emp) => parseInt(emp.codpuesto))),
        ],
        puestos = [];
      if (coddepartamento > 0) {
        codpuestos = [
          ...new Set(
            this.empleados
              .filter(
                (emp) =>
                  parseInt(emp.coddepartamento) === parseInt(coddepartamento)
              )
              ?.map((emp) => parseInt(emp.codpuesto))
          ),
        ];
      }

      if (codpuestos.length > 0) {
        puestos = codpuestos.map((cod) => {
          const { nombrePuesto } = this.empleados.find(
            (emp) => parseInt(emp.codpuesto) === cod
          );

          return { codpuesto: cod, nombrePuesto };
        });
      }

      opciones = puestos.map(
        (puesto) =>
          `<option value="${puesto.codpuesto}">${puesto.nombrePuesto}</option>`
      );

      opciones.length > 1 &&
        opciones.unshift(`<option value="0">Todos los puestos</option>`);

      opciones.length > 0
        ? opciones.unshift(
            '<option value="" selected disabled>Seleccione</option>'
          )
        : opciones.unshift(
            '<option value="" selected disabled>No hay puestos disponibles</option>'
          );
    }

    this.campos.puesto.innerHTML = opciones.join("");

    $(`#${this.campos.puesto.id}`).selectpicker("destroy").selectpicker();

    this.evaluarPuesto();
  },
  evaluarPuesto: function () {
    const codpuesto = this.campos.puesto.value,
      coddepartamento = this.campos.departamento.value,
      tipoAsignacion = this.campos.tipoAsignacion.value;

    let opciones = [
      `<option value="" selected disabled>Seleccione un puesto</option>`,
    ];

    if (codpuesto && parseInt(tipoAsignacion) == 2) {
      let codempleados = [
          ...new Set(this.empleados.map((emp) => parseInt(emp.codempleado))),
        ],
        empleados = [];

      if (codpuesto > 0) {
        if (coddepartamento > 0) {
          codempleados = [
            ...new Set(
              this.empleados
                .filter(
                  (emp) =>
                    parseInt(emp.codpuesto) === parseInt(codpuesto) &&
                    parseInt(emp.coddepartamento) === parseInt(coddepartamento)
                )
                ?.map((emp) => parseInt(emp.codempleado))
            ),
          ];
        } else {
          codempleados = [
            ...new Set(
              this.empleados
                .filter(
                  (emp) => parseInt(emp.codpuesto) === parseInt(codpuesto)
                )
                ?.map((emp) => parseInt(emp.codempleado))
            ),
          ];
        }
      }

      if (codempleados.length > 0) {
        empleados = codempleados.map((cod) => {
          const { nombreCompleto, codempleado: codigo } = this.empleados.find(
            (emp) => parseInt(emp.codempleado) === cod
          );

          return { codempleado: codigo, nombreEmpleado: nombreCompleto };
        });
      }

      opciones = empleados.map(
        (empleado) =>
          `<option value="${empleado.codempleado}">${empleado.nombreEmpleado}</option>`
      );

      opciones.length > 0
        ? opciones.unshift(
            '<option value="" selected disabled>Seleccione</option>'
          )
        : opciones.unshift(
            '<option value="" selected disabled>No hay empleados disponibles</option>'
          );
    }

    this.campos.empleado.innerHTML = opciones.join("");

    $(`#${this.campos.empleado.id}`).selectpicker("destroy").selectpicker();
  },
  calcularCantidadEmpleados: function ({ detalles }) {
    let totalEmpleados = 0;
    let asignacionesEmpleados = detalles.filter(
        (detalle) => parseInt(detalle.idTipoAsignacion) === 2
      ),
      asignacionesUnidades = detalles.filter(
        (detalle) => parseInt(detalle.idTipoAsignacion) === 1
      ),
      asignacionesCargos = detalles.filter(
        (detalle) => parseInt(detalle.idTipoAsignacion) === 3
      );

    let codempleados = asignacionesEmpleados.map((detalle) =>
        parseInt(detalle.idAsignacion)
      ),
      unidades = asignacionesUnidades.map((detalle) =>
        parseInt(detalle.idAsignacion)
      ),
      cargos = asignacionesCargos.map((detalle) =>
        parseInt(detalle.idAsignacion)
      );

    if (codempleados.length > 0) {
      codempleados = [...new Set(codempleados)];
    }

    if (unidades.length > 0) {
      unidades = [...new Set(unidades)];

      let empleadosUnidades = this.empleados
        .filter((emp) => unidades.includes(parseInt(emp.idUnidadTrabajo)))
        .map((emp) => parseInt(emp.codempleado));

      if (empleadosUnidades.length > 0) {
        empleadosUnidades = [...new Set(empleadosUnidades)];
      }

      empleadosUnidades = empleadosUnidades.filter(
        (emp) => !codempleados.includes(emp)
      );

      codempleados = [...codempleados, ...empleadosUnidades];
    }

    if(cargos.length > 0){
      cargos = [...new Set(cargos)];

      let empleadosCargos = this.empleados
        .filter((emp) => cargos.includes(parseInt(emp.codpuesto)))
        .map((emp) => parseInt(emp.codempleado));

      if (empleadosCargos.length > 0) {
        empleadosCargos = [...new Set(empleadosCargos)];
      }

      empleadosCargos = empleadosCargos.filter(
        (emp) => !codempleados.includes(emp)
      );

      codempleados = [...codempleados, ...empleadosCargos];
    }

    totalEmpleados = codempleados.length;

    return totalEmpleados;
  },
};
