import Permiso from "../models/permisoModel.js?v=1.0.0";
import CustomDataTable from "../app/CustomDataTable.js?v=1.0.0";
import Modulo from "../models/moduloModel.js?v=1.0.0";
import Apartado from "../models/apartadoModel.js?v=1.0.0";
import Usuario from "../models/usuarioModel.js?v=1.0.0";
import Rol from "../models/rolModel.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";

!(function () {
  document.getElementById("btn-regresar").addEventListener("click", () => {
    configModuloApartado.regresar();
  });

  document.getElementById("btn-permiso").addEventListener("click", () => {
    configPermiso.editar();
  });

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

  document
    .getElementById("cbo-tipo-asignacion")
    .addEventListener("change", () => {
      configPermiso.evaluarTipoAsignacion();
    });

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

    if (target.classList.contains("configurar-sub")) {
      configModuloApartado.configurarSub({ id: target.dataset.id });
    }

    if (target.classList.contains("eliminar-permiso")) {
      configPermiso.eliminar(target.dataset.id);
    }

    if (target.classList.contains("editar-permiso")) {
      configPermiso.editar(target.dataset.id);
    }
  });
})();

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

function inicializarTablas() {
  return new Promise((resolve, reject) => {
    try {
      configPermiso.tabla = new CustomDataTable({
        id: "permisos-tbl",
        alineadoIzquierda: [1, 2, 3],
        noOrdenable: [4],
      });

      configModuloApartado.tabla = new CustomDataTable({
        id: "modulos-apartados-tbl",
        alineadoIzquierda: [1, 2],
        noOrdenable: [3],
        filaSeleccionable: false,
      });

      $("#modulos-apartados-tbl tbody").on("click", "td", function () {
        if ($(this).closest("tr").attr("id") && $(this).index() != 3) {
          if ($(this).closest("tr").hasClass("selected")) {
            $(this).closest("tr").removeClass("selected");
            configPermiso.limpiar();
            configModuloApartado.id = 0;
          } else {
            configModuloApartado.tabla.tabla
              .$("tr.selected")
              .removeClass("selected");
            $(this).closest("tr").addClass("selected");
            let id = $(this).closest("tr").attr("id").replace("trConfig", "");
            configPermiso.inicializar({ id });
            configModuloApartado.id = id;
          }
        }
      });
      resolve();
    } catch (err) {
      reject(err);
    }
  });
}

const configPermiso = {
  id: 0,
  cnt: 0,
  data: {},
  tabla: null,
  campos: {
    tipoAsignacion: document.getElementById("cbo-tipo-asignacion"),
    asignacion: document.getElementById("cbo-asignacion"),
    tipoPermiso: document.getElementById("cbo-tipo-permiso"),
  },
  catalogos: {
    roles: [],
    usuarios: [],
  },
  modal: {
    id: "modal-permiso",
    mostrar: () => $(`#${configPermiso.modal.id}`).modal("show"),
    ocultar: () => $(`#${configPermiso.modal.id}`).modal("hide"),
  },
  form: "permiso-form",
  inicializar: async function ({ id }) {
    try {
      await this.limpiar();

      const tipo = configModuloApartado.tipo,
        idBusqueda = configModuloApartado.obtenerPorId({ id })?.id || 0;

      let { data: permisos = [] } = await Permiso.obtenerPorContenedor({
        tipoContenedor: tipo,
        idContenedor: idBusqueda,
      });

      permisos.forEach((permiso) => {
        this.cnt++;
        this.data[this.cnt] = permiso;

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

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

      this.tabla.redibujar();
      document.getElementById("btn-permiso").disabled = false;
    } catch (err) {
      mostrarMensajes.error(err);
    }
  },
  editar: async function (id = 0) {
    try {
      await metodosFormularios.limpiar({ id: this.form });

      this.id = id;

      let asignacion = null;

      if (this.id > 0) {
        const permiso = this.data[this.id];
        this.campos.tipoAsignacion.value = permiso.idTipoAsignacion;
        asignacion = permiso.idAsignacion;
        this.campos.tipoPermiso.value = permiso.idTipoPermiso;
      }

      await this.evaluarTipoAsignacion(asignacion);
      this.campos.asignacion.value = asignacion;

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

    try {
      let permiso = new Permiso({
        id: this.data[this.id]?.id || 0,
        tipoContenedor: configModuloApartado.tipo,
        contenedor:
          configModuloApartado.obtenerPorId({ id: configModuloApartado.id })
            ?.id || 0,
        idTipoAsignacion: this.campos.tipoAsignacion.value,
        tipoAsignacion:
          this.campos.tipoAsignacion.options[
            this.campos.tipoAsignacion.selectedIndex
          ].text,
        idAsignacion: this.campos.asignacion.value,
        asignacion:
          this.campos.asignacion.options[this.campos.asignacion.selectedIndex]
            .text,
        idTipoPermiso: this.campos.tipoPermiso.value,
        tipoPermiso:
          this.campos.tipoPermiso.options[this.campos.tipoPermiso.selectedIndex]
            .text,
      });

      const respuesta = await permiso.guardar();

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

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

          this.data[this.id] = permiso;

          this.modal.ocultar();

          mostrarToastify({
            type: "success",
            message: `Datos guardados con éxito`,
          });
          break;
        default:
          mostrarMensajes.error(respuesta);
          break;
      }
    } catch (err) {
      mostrarMensajes.error(err);
    }
  },
  eliminar: async function (id = 0) {
    const permiso = this.data[id];

    try {
      const confirmacion = await mostrarMensajes.confirm({
        message: `Se eliminará el permiso de <strong>${permiso.asignacion}</strong> <br /> Esta acción no se puede deshacer`,
      });

      if (!confirmacion) return;

      const respuesta = await Permiso.eliminar({ id: permiso.id });

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

          mostrarToastify({
            type: "success",
            message: `Permiso eliminado con éxito`,
          });
          break;
        default:
          mostrarMensajes.error(respuesta);
          break;
      }
    } catch (err) {
      if (!!err) mostrarMensajes.error(err);
    }
  },
  evaluarTipoAsignacion: function (asignacion = null) {
    return new Promise(async (resolve) => {
      try {
        let tipoAsignacion = this.campos.tipoAsignacion.value,
          datos = [];

        if (!!tipoAsignacion) {
          if (tipoAsignacion == "rol") {
            let { data: roles = [] } = await Rol.obtenerTodos();
            datos = roles.map((rol) => ({ id: rol.id, label: rol.rol }));
          }

          if (tipoAsignacion == "usuario") {
            let { data: usuarios = [] } = await Usuario.obtenerTodosParaCombo();
            datos = usuarios.map((usuario) => ({
              id: usuario.id,
              label: usuario.nombreCompleto,
            }));
          }
        }

        let asignados = Object.values(this.data)
          .filter((d) => d.idTipoAsignacion == tipoAsignacion)
          .map((d) => parseInt(d.idAsignacion));

        if (!!asignacion) {
          asignados = asignados.filter((a) => a != parseInt(asignacion));
        }

        let opciones = datos
          .filter((d) => !asignados.includes(parseInt(d.id)))
          .map((d) => `<option value="${d.id}">${d.label}</option>`);

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

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

        if (!!asignacion) {
          this.campos.asignacion.value = asignacion;
        }

        $(`#${this.campos.asignacion.id}`)
          .selectpicker("destroy")
          .selectpicker();
        resolve();
      } catch (err) {
        mostrarMensajes.error(err);
        throw err;
      }
    });
  },
  prepararParaFila: function ({ datos, id }) {
    return {
      0: id,
      1: datos.tipoAsignacion,
      2: datos.asignacion,
      3: datos.tipoPermiso,
      4: obtenerHTMLBotonesDropdown([
        {
          tipo: "edit",
          selectorClase: "editar-permiso",
          selectorId: id,
          texto: "Editar",
        },
        {
          tipo: "delete",
          selectorClase: "eliminar-permiso",
          selectorId: id,
          texto: "Eliminar",
        },
      ]),
    };
  },
  limpiar: function () {
    return new Promise(async (resolve) => {
      this.cnt = 0;
      this.id = 0;
      this.data = {};
      this.tabla.limpiar().redibujar();
      document.getElementById("btn-permiso").disabled = true;
      resolve();
    });
  },
};

const configModuloApartado = {
  id: 0,
  cnt: 0,
  data: {},
  tipo: "modulo",
  arrIds: [],
  arrUbicacion: [],
  nivel: 0,
  tabla: null,
  catalogos: {
    modulos: [],
    apartados: [],
  },
  inicializar: function ({ datos = [] }) {
    return new Promise(async (resolve, reject) => {
      try {
        await this.limpiar();

        datos.forEach((dato) => {
          this.cnt++;
          this.data[this.cnt] = dato;

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

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

        this.tabla.redibujar();

        document.getElementById("btn-regresar").disabled = this.nivel == 0;

        await configPermiso.limpiar();

        resolve();
      } catch (err) {
        reject(err);
      }
    });
  },
  configurar: function (id = 0) {
    return new Promise(async (resolve, reject) => {
      try {
        let datos = [];
        if (this.tipo == "modulo") {
          let { data: modulos = [] } = await Modulo.obtenerTodos();
          this.catalogos.modulos = modulos;

          datos = modulos.map((mod) => ({ ...mod, apartados: 1 }));
        }

        if (this.tipo == "apartado" && this.nivel == 1) {
          let { data: apartados = [] } = await Apartado.obtenerPorModulo({
            idModulo: id,
          });

          this.catalogos.apartados = apartados;
          datos = apartados.map((apart) => ({
            ...apart,
            apartados: apart.subApartados?.length || 0,
          }));
        }

        if (this.tipo == "apartado" && this.nivel > 1) {
          let { data: apartados = [] } = await Apartado.obtenerPorSuperior({
            idSuperior: id,
            nivel: this.nivel,
          });
          this.catalogos.apartados = apartados;
          datos = apartados.map((apart) => ({
            ...apart,
            apartados: apart.subApartados?.length || 0,
          }));
        }

        await this.inicializar({ datos });

        resolve();
      } catch (err) {
        reject(err);
      }
    });
  },
  prepararParaFila: function ({ datos, id }) {
    let botones =
      this.nivel == 4 || datos.apartados == 0
        ? ``
        : obtenerHTMLBotonesDropdown([
            {
              tipo: "custom",
              icono: "fa-solid fa-gears",
              selectorClase: "configurar-sub",
              selectorId: id,
              texto: this.nivel == 0 ? "Ver apartados" : "Ver sub apartados",
            },
          ]);
    return {
      0: id,
      1: datos.titulo,
      2: datos.descripcion,
      3: botones,
    };
  },
  limpiar: function () {
    return new Promise(async (resolve) => {
      this.tabla.limpiar().redibujar();
      this.id = 0;
      this.cnt = 0;
      this.data = {};
      resolve();
    });
  },
  obtenerPorId: function ({ id }) {
    return this.data[id] || {};
  },
  configurarSub: function ({ id }) {
    let tipo = "apartado",
      nivel = this.nivel + 1,
      tmp = this.data[id];

    let tituloHTML = `<ol class="breadcrumb m-0">
    ${this.arrUbicacion
      .map((t) => `<li class="breadcrumb-item">${t}</li>`)
      .join("")}
    <li class="breadcrumb-item active">${tmp?.titulo || "Sin apartado"}</li>
    </ol>`;

    this.arrUbicacion.push(tmp?.titulo || "Sin apartado");
    this.tipo = tipo;
    this.nivel = nivel;

    this.arrIds[nivel] = tmp?.id || 0;
    document.getElementById("spn-ubicacion").innerHTML = tituloHTML;
    this.configurar(tmp?.id || 0);
  },
  regresar: function () {
    let nivel = this.nivel - 1,
      tipo = nivel == 0 ? "modulo" : "apartado";

    this.arrUbicacion.pop();

    let ultimo = this.arrUbicacion[this.arrUbicacion.length - 1],
      tituloHTML = ``;

    if (nivel > 0) {
      tituloHTML = `<ol class="breadcrumb m-0">
      ${this.arrUbicacion
        .map((t, index) => {
          return index < this.arrUbicacion.length - 1
            ? `<li class="breadcrumb-item">${t}</li>`
            : null;
        })
        .join("")}
      <li class="breadcrumb-item active">${ultimo}</li>
      </ol>`;
    }

    document.getElementById("spn-ubicacion").innerHTML = tituloHTML;
    this.nivel = nivel;
    this.tipo = tipo;

    this.configurar(this.arrIds[nivel]);
  },
};
