"use strict";

import CustomDataTable from "../app/CustomDataTable.js?v=1.0.0";
import {
  obtenerHTMLBotonesDropdown,
  mostrarMensajes,
  mostrarToastify,
} from "../app/funcionesGenerales.js?v=1.0.0";
import metodosFormularios from "../app/metodosFormularios.js?v=1.0.0";
import RubroEmpresa from "../models/rubroEmpresaModel.js?v=1.0.0";
import Empresa from "../models/empresaModel.js?v=1.0.0";
import Modulo from "../models/moduloModel.js?v=1.0.0";

!(function () {
  document
    .getElementById("btn-agregar-empresa")
    .addEventListener("click", () => {
      configEmpresa.editar();
    });

  document
    .getElementById("btn-cancelar-empresa")
    .addEventListener("click", () => {
      configEmpresa.cancelar();
    });

  document.getElementById("btn-asignar-rubro").addEventListener("click", () => {
    configRubro.editar();
  });

  document
    .getElementById("btn-asignar-modulo")
    .addEventListener("click", () => {
      configModulo.editar();
    });

  document.getElementById("rubro-form").addEventListener("submit", (e) => {
    e.preventDefault();
    configRubro.guardar();
  });

  document.getElementById("modulo-form").addEventListener("submit", (e) => {
    e.preventDefault();
    configModulo.guardar();
  });

  document.getElementById("empresa-form").addEventListener("submit", (e) => {
    e.preventDefault();
    configEmpresa.guardar();
  });

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

    target.classList.contains("eliminar-rubro") &&
      configRubro.eliminar(target.dataset.id);

    target.classList.contains("eliminar-modulo") &&
      configModulo.eliminar(target.dataset.id);

    target.classList.contains("editar-empresa") &&
      configEmpresa.editar(target.dataset.id);

    target.classList.contains("eliminar-empresa") &&
      configEmpresa.eliminar(target.dataset.id);
  });
})();

window.onload = () => {
  inicializarTablas()
    .then(() => configRubro.inicializar())
    .then(() => configModulo.inicializar())
    .then(() => configEmpresa.inicializar())
    .then(() => {
      document.querySelector(".loader") &&
        document.querySelector(".loader").classList.add("d-none");
    })
    .catch(mostrarMensajes.error);
};

function inicializarTablas() {
  return new Promise((resolve, reject) => {
    try {
      configEmpresa.tabla = new CustomDataTable({
        id: "empresas-tbl",
        alineadoIzquierda: [3],
        noOrdenable: [5],
      });

      configRubro.tabla = new CustomDataTable({
        id: "rubros-tbl",
        alineadoIzquierda: [1],
        noOrdenable: [2],
      });

      configModulo.tabla = new CustomDataTable({
        id: "modulos-tbl",
        alineadoIzquierda: [1],
        noOrdenable: [2],
      });
      resolve();
    } catch (err) {
      reject(err);
    }
  });
}

const configEmpresa = {
  id: 0,
  cnt: 0,
  data: {},
  tabla: null,
  form: "empresa-form",
  tabs: {
    empresas: document.getElementById("empresas-tab"),
    edicion: document.getElementById("editar-empresa-tab"),
  },
  botones: {
    nuevo: document.getElementById("btns-nueva-empresa"),
    guardar: document.getElementById("btns-guardar-empresa"),
  },
  campos: {
    principal: document.getElementById("chk-empresa-principal"),
    nombre: document.getElementById("txt-nombre-empresa"),
    codempresa: document.getElementById("num-codempresa"),
    urlApi: document.getElementById("txt-url-api"),
    apiKey: document.getElementById("txt-api-key"),
  },
  inicializar: function () {
    return new Promise(async (resolve, reject) => {
      try {
        const { data: empresas = [] } = await Empresa.obtenerTodos();

        empresas.forEach((empresa) => {
          this.cnt++;

          this.data[this.cnt] = empresa;

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

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

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

    this.id = id;

    let rubros = [],
      modulos = [];

    if (this.id > 0) {
      const empresa = this.data[this.id];
      this.campos.principal.checked = empresa.principal == 1;
      this.campos.nombre.value = empresa.nombreEmpresa;
      this.campos.codempresa.value = empresa.codempresa;
      this.campos.urlApi.value = empresa.urlApi;
      this.campos.apiKey.value = empresa.apiKey;

      let { data: tmpRubros = [] } = await Empresa.obtenerRubros({
          id: empresa.id,
        }),
        { data: tmpModulos = [] } = await Empresa.obtenerModulos({
          id: empresa.id,
        });

      rubros = tmpRubros;
      modulos = tmpModulos;
    }

    await configRubro.configurar({ rubrosAsignados: rubros });
    await configModulo.configurar({ modulosAsignados: modulos });

    [...Object.values(this.tabs)].forEach((tab) =>
      tab.classList.toggle("disabled")
    );

    [...Object.values(this.botones)].forEach((btn) =>
      btn.classList.toggle("d-none")
    );

    this.tabs.edicion.click();
  },
  guardar: async function () {
    if (!metodosFormularios.validar({ id: this.form })) return;

    const rubros = configRubro.obtenerDatos();
    const modulos = configModulo.obtenerDatos();

    if (rubros.length == 0) {
      mostrarToastify({
        type: "info",
        message: "Debe asignar al menos un rubro a la empresa",
      });
      return;
    }

    try {
      const empresa = new Empresa({
        id: this.data[this.id]?.id || 0,
        principal: this.campos.principal.checked ? 1 : 0,
        nombreEmpresa: this.campos.nombre.value,
        codempresa: this.campos.codempresa.value,
        urlApi: this.campos.urlApi.value,
        apiKey: this.campos.apiKey.value,
        rubros,
        modulos,
        fechaRegistro:
          this.data[this.id]?.fechaRegistro ||
          moment().format("DD-MM-YYYY HH:mm:ss"),
      });

      const respuesta = await empresa.guardar();

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

          const fila = this.prepararParaFila({
            datos: empresa,
            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: `trEmpresa${this.id}` })
              .redibujar();
          } else {
            this.tabla
              .actualizarFila({ datos: fila, idFila: `trEmpresa${this.id}` })
              .redibujar();
          }

          this.data[this.id] = empresa;

          mostrarToastify({
            type: "success",
            message: "Empresa guardada correctamente",
          });
          this.cancelar();
          break;
        case "duplicado":
          mostrarMensajes.warning({
            message: "Ya existe una empresa con ese codempresa",
          });
          break;
        default:
          mostrarMensajes.error(respuesta);
          break;
      }
    } catch (err) {
      mostrarMensajes.error(err);
    }
  },
  eliminar: function (id = 0) {},
  cancelar: function () {
    [...Object.values(this.tabs)].forEach((tab) =>
      tab.classList.toggle("disabled")
    );

    [...Object.values(this.botones)].forEach((btn) =>
      btn.classList.toggle("d-none")
    );

    this.tabs.empresas.click();
  },
  prepararParaFila: function ({ datos, id }) {
    let indicadorPrincipal =
      datos.principal == 1
        ? `<i class="fa-solid fa-star text-warning"></i>`
        : "";

    return {
      0: id,
      1: indicadorPrincipal,
      2: datos.codempresa,
      3: datos.nombreEmpresa,
      4: datos.fechaRegistro,
      5: obtenerHTMLBotonesDropdown([
        {
          tipo: "edit",
          texto: "Editar",
          selectorClase: "editar-empresa",
          selectorId: id,
        },
        {
          tipo: "delete",
          texto: "Eliminar",
          selectorClase: "eliminar-empresa",
          selectorId: id,
        },
      ]),
    };
  },
};

const configRubro = {
  id: 0,
  cnt: 0,
  data: {},
  tabla: null,
  campos: {
    rubro: document.getElementById("cbo-rubro"),
  },
  catalogo: [],
  form: "rubro-form",
  modal: {
    id: "modal-rubro",
    mostrar: () => $(`#${configRubro.modal.id}`).modal("show"),
    ocultar: () => $(`#${configRubro.modal.id}`).modal("hide"),
  },
  inicializar: function () {
    return new Promise(async (resolve, reject) => {
      try {
        const { data: rubros = [] } = await RubroEmpresa.obtenerTodos();

        this.catalogo = rubros;
        resolve();
      } catch (err) {
        reject(err);
      }
    });
  },
  configurar: function ({ rubrosAsignados = [] }) {
    return new Promise(async (resolve) => {
      await this.limpiar();
      rubrosAsignados.forEach((rubro) => {
        this.cnt++;
        this.data[this.cnt] = rubro;

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

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

      this.tabla.redibujar();
      resolve();
    });
  },
  editar: async function (id = 0) {
    try {
      await metodosFormularios.limpiar({ id: this.form });

      this.id = id;

      const rubroSeleccionado = this.data[this.id] || {};

      const rubrosAsignados = Object.values(this.data)
        .filter(
          (r) =>
            parseInt(r.idRubro) != parseInt(rubroSeleccionado?.idRubro || 0)
        )
        .map((r) => parseInt(r.idRubro));

      let opciones = this.catalogo
        .filter((r) => !rubrosAsignados.includes(parseInt(r.id)))
        .map((r) => `<option value="${r.id}">${r.rubro}</option>`);

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

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

      if (this.id > 0) {
        const rubro = this.data[this.id];

        this.campos.rubro.value = rubro.idRubro;
      }

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

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

    const datos = {
      id: this.data[this.id]?.id || 0,
      idRubro: this.campos.rubro.value,
      rubro: this.campos.rubro.options[this.campos.rubro.selectedIndex].text,
      fechaRegistro:
        this.data[this.id]?.fechaRegistro ||
        moment().format("DD-MM-YYYY HH:mm a"),
    };

    const fila = this.prepararParaFila({
      datos,
      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: `trRubro${this.id}` })
        .redibujar();
    } else {
      this.tabla
        .actualizarFila({ datos: fila, idFila: `trRubro${this.id}` })
        .redibujar();
    }

    this.data[this.id] = datos;

    this.modal.ocultar();

    mostrarToastify({
      type: "success",
      message: "Rubro guardado correctamente",
    });
  },
  eliminar: async function (id = 0) {
    const rubro = this.data[id];

    try {
      const confirmacion = await mostrarMensajes.confirm({
        message: `Se eliminará el rubro <strong>${rubro.rubro}</strong> para esta empresa`,
      });

      if (!confirmacion) return;

      delete this.data[id];
      this.tabla.eliminarFila({ idFila: `trRubro${id}` }).redibujar();
      mostrarToastify({
        type: "success",
        message: "Rubro eliminado correctamente",
      });
    } catch (err) {
      if (!!err) mostrarMensajes.error(err);
    }
  },
  limpiar: function () {
    return new Promise((resolve) => {
      this.id = 0;
      this.cnt = 0;
      this.data = {};
      !!this.tabla && this.tabla.limpiar().redibujar();
      resolve();
    });
  },
  prepararParaFila: function ({ datos, id }) {
    return {
      0: id,
      1: datos.rubro,
      2: obtenerHTMLBotonesDropdown([
        {
          tipo: "delete",
          texto: "Eliminar",
          selectorClase: "eliminar-rubro",
          selectorId: id,
        },
      ]),
    };
  },
  obtenerDatos: function () {
    return Object.values(this.data);
  },
};

const configModulo = {
  id: 0,
  cnt: 0,
  data: {},
  tabla: null,
  campos: {
    modulo: document.getElementById("cbo-modulo"),
  },
  catalogo: [],
  form: "modulo-form",
  modal: {
    id: "modal-modulo",
    mostrar: () => $(`#${configModulo.modal.id}`).modal("show"),
    ocultar: () => $(`#${configModulo.modal.id}`).modal("hide"),
  },
  inicializar: function () {
    return new Promise(async (resolve, reject) => {
      try {
        const { data: modulos = [] } = await Modulo.obtenerTodosParaCombo();

        this.catalogo = modulos;

        resolve();
      } catch (err) {
        reject(err);
      }
    });
  },
  configurar: function ({ modulosAsignados = [] }) {
    return new Promise(async (resolve) => {
      await this.limpiar();

      modulosAsignados.forEach((modulo) => {
        this.cnt++;
        this.data[this.cnt] = modulo;

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

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

      this.tabla.redibujar();
      resolve();
    });
  },
  editar: async function (id = 0) {
    try {
      await metodosFormularios.limpiar({ id: this.form });

      this.id = id;

      const moduloSeleccionado = this.data[this.id] || {};

      const modulosAsignados = Object.values(this.data)
        .filter(
          (r) =>
            parseInt(r.idModulo) != parseInt(moduloSeleccionado?.idModulo || 0)
        )
        .map((r) => parseInt(r.idModulo));

      let opciones = this.catalogo
        .filter((r) => !modulosAsignados.includes(parseInt(r.id)))
        .map((r) => `<option value="${r.id}">${r.titulo}</option>`);

      opciones.length > 0
        ? opciones.unshift(
            `<option value="" selected disabled>Seleccione</option>`
          )
        : opciones.unshift(
            `<option value="" selected disabled>No hay módulos disponibles</option>`
          );

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

      if (this.id > 0) {
        this.campos.modulo.value = moduloSeleccionado?.idModulo || 0;
      }

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

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

    const datos = {
      id: this.data[this.id]?.id || 0,
      idModulo: this.campos.modulo.value,
      modulo: this.campos.modulo.options[this.campos.modulo.selectedIndex].text,
      fechaRegistro:
        this.data[this.id]?.fechaRegistro ||
        moment().format("DD-MM-YYYY HH:mm a"),
    };

    const fila = this.prepararParaFila({
      datos,
      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: `trModulo${this.id}` })
        .redibujar();
    } else {
      this.tabla
        .actualizarFila({ datos: fila, idFila: `trModulo${this.id}` })
        .redibujar();
    }

    this.data[this.id] = datos;

    this.modal.ocultar();

    mostrarToastify({
      type: "success",
      message: "Módulo guardado correctamente",
    });
  },
  eliminar: async function (id = 0) {
    const modulo = this.data[id];

    try {
      const confirmacion = await mostrarMensajes.confirm({
        message: `Se eliminará el módulo <strong>${modulo.modulo}</strong> para esta empresa`,
      });

      if (!confirmacion) return;

      delete this.data[id];
      this.tabla.eliminarFila({ idFila: `trModulo${id}` }).redibujar();
      mostrarToastify({
        type: "success",
        message: "Módulo eliminado correctamente",
      });
    } catch (err) {
      if (!!err) mostrarMensajes.error(err);
    }
  },
  limpiar: function () {
    return new Promise((resolve) => {
      this.id = 0;
      this.cnt = 0;
      this.data = {};
      !!this.tabla && this.tabla.limpiar().redibujar();
      resolve();
    });
  },
  prepararParaFila: function ({ datos, id }) {
    return {
      0: id,
      1: datos.modulo,
      2: obtenerHTMLBotonesDropdown([
        {
          tipo: "delete",
          texto: "Eliminar",
          selectorClase: "eliminar-modulo",
          selectorId: id,
        },
      ]),
    };
  },
  obtenerDatos: function () {
    return Object.values(this.data);
  },
};
