const customQuery = require("../utils/databaseCustomQueryHelper");
const artigoPorGrupoValidade = require("../services/artigoPorGrupoValidadeService");
const { Result } = require("express-validator");
const logger = require("../utils/logger");

const getDashboardData = async (userId, maquinaId) => {
  try {
    const tableNameArtigos = "tbl_Artigos";
    const whereClauseArtigos = "bitEliminado = 0";

    const resultNomeArtigos = await customQuery.executeDynamicQueryWithWhere(
      tableNameArtigos,
      whereClauseArtigos
    );

    //Carregar justificacoes
    const tableNameJustificacoes = "tbl_Justificacoes";
    const whereClauseJustificacoes = "bitEliminado = 0";
    const resultJustificacoes = await customQuery.executeDynamicQueryWithWhere(
      tableNameJustificacoes,
      whereClauseJustificacoes
    );

    const tableNameIdGrupo = "tbl_Funcionarios";
    const whereClauseIdGrupo = "intId = :intIdUser";
    const queryParamsIdGrupo = { intIdUser: userId };

    const resultIdGrupo = await customQuery.executeDynamicQueryWithWhere(
      tableNameIdGrupo,
      whereClauseIdGrupo,
      queryParamsIdGrupo
    );

    let returnArray = [];
    const idGrupoUser = resultIdGrupo[0].intIdGrupo;

    const parameters = {
      intIdGrupo: idGrupoUser,
    };
    const data = await customQuery.executeDynamicQuery(
      "View_Front_ValidadeArtigosPorGrupo",
      parameters
    );

    const arrayArtigosMensal = [];
    const arrayArtigosPeriodoVariavel = [];

    data.forEach((item) => {
      if (item.bitIsMensal) {
        arrayArtigosMensal.push(item);
      } else {
        arrayArtigosPeriodoVariavel.push(item);
      }
    });

    const mesAtual = getCurrentMonthNumber();
    const anoAtual = getCurrentYear();
    const diaAtual = getCurrentDay();
    for (const item of arrayArtigosMensal) {
      let mesControlo;
      let anoControlo;
      if (item.intNumeroMesControlo == null) {
        mesControlo = item.intNumeroMesInicio;
        anoControlo = item.intNumeroAnoInicio;
      } else {
        mesControlo = item.intNumeroMesControlo;
        anoControlo = item.intNumeroAnoControlo;
      }

      if (anoAtual > anoControlo || mesAtual > mesControlo) {
        const result = addMonthsIncrementally(
          mesControlo,
          anoControlo,
          mesAtual,
          anoAtual,
          1
        );
        const { newMonth, newYear, previousNewMonth, previousNewYear } = result;
        const updateData = {
          intNumeroMesControlo: previousNewMonth,
          intNumeroAnoControlo: previousNewYear,
        };

        await artigoPorGrupoValidade.updateArtigoPorGrupoValidade(
          item.intIdLinhaArtigosPorGrupoValidade,
          updateData
        );
      }
    }

    const intIdArtigoArray = arrayArtigosMensal.map((item) => item.intIdArtigo);

    const viewName = "view_Front_MovimentosMaquinaAnoMes";
    const whereClause =
      "ano = :ano AND mes = :mes AND intIdUser = :intIdUser AND intIdArtigo IN (:intIdArtigo)";
    const queryParams = {
      ano: anoAtual,
      mes: mesAtual,
      intIdUser: userId,
      intIdArtigo: intIdArtigoArray,
    };

    const result1 = await customQuery.executeDynamicQueryWithWhere(
      viewName,
      whereClause,
      queryParams
    );

    returnArray.push(...result1);

    const whereClauseArtigosPeriodoVariavel =
      "intIdUser = :intIdUser AND intIdArtigo = :intIdArtigo AND ano >= :startYear AND ano <= :endYear AND mes >= :startMonth AND mes <= :endMonth";
    const viewFieldsArtigosPeriodoVariavel =
      "[intIdUser], [intIdArtigo], SUM([qtdLevantada]) as qtdLevantada, [intQtdMax], [intQtdMaxDia], [intIdGrupo], [intPeriodoMeses]";
    const groupByClauseArtigosPeriodoVariavel =
      "[intIdUser], [intIdArtigo], [intQtdMax], [intQtdMaxDia], [intIdGrupo], [intPeriodoMeses]";

    const resultArtigosValidadeVariavel = [];
    for (const item of arrayArtigosPeriodoVariavel) {
      let mesControlo;
      let anoControlo;
      if (item.intNumeroMesControlo == null) {
        mesControlo = item.intNumeroMesInicio;
        anoControlo = item.intNumeroAnoInicio;
      } else {
        mesControlo = item.intNumeroMesControlo;
        anoControlo = item.intNumeroAnoControlo;
      }

      const result2 = addMonthsIncrementally(
        mesControlo,
        anoControlo,
        mesAtual,
        anoAtual,
        item.intPeriodoMeses,
        false
      );

      const { newMonth, newYear, previousNewMonth, previousNewYear } = result2;

      const updateData = {
        intNumeroMesControlo: previousNewMonth,
        intNumeroAnoControlo: previousNewYear,
      };

      if (anoAtual > anoControlo || mesAtual > mesControlo) {
        await artigoPorGrupoValidade.updateArtigoPorGrupoValidade(
          item.intIdLinhaArtigosPorGrupoValidade,
          updateData
        );
      }

      const queryParamsArtigosPeriodoVariavel = {
        intIdUser: userId,
        intIdArtigo: item.intIdArtigo,
        startYear: previousNewYear,
        endYear: newYear,
        startMonth: previousNewMonth,
        endMonth: newMonth,
      };

      const result = await customQuery.executeDynamicQueryWithWhereAndGroupBy(
        viewName,
        whereClauseArtigosPeriodoVariavel,
        viewFieldsArtigosPeriodoVariavel,
        groupByClauseArtigosPeriodoVariavel,
        queryParamsArtigosPeriodoVariavel
      );
      resultArtigosValidadeVariavel.push(...result);
    }

    returnArray.push(...resultArtigosValidadeVariavel);

    const viewName2 = "view_Front_ArtigosPorGrupoAll";
    const whereClause2 = "intIdGrupo = :intIdGrupo";
    const queryParams2 = { intIdGrupo: idGrupoUser };

    const result1_1 = await customQuery.executeDynamicQueryWithWhere(
      viewName2,
      whereClause2,
      queryParams2
    );

    if (result1_1.length > 0) {
      const filteredResult = result1_1.filter(
        (item) =>
          !returnArray.some(
            (returnItem) => returnItem.intIdArtigo === item.intIdArtigo
          )
      );
      // Adding new columns to each item
      filteredResult.forEach((item) => {
        item.qtdLevantada = 0; // Adding qtdLevantada column with default value 0
        item.intIdUser = userId;
        //item.stringCaminhoImagem = item.stringCaminhoImagem || null;
        // Adding newColumn with empty string value
      });

      returnArray.push(...filteredResult);
    } else {
      console.log("Result is empty");
    }
    //  console.log(returnArray);
    // Iterate over returnArray

    const intIdArtigoArrayReturn = returnArray.map((item) => item.intIdArtigo);

    //Validar Stock Maquina
    const viewNameStockMaquina = "[db_owner].[View_StockMaquinaPosicao]";
    const whereClauseStockMaquina =
      "intIdMaq = :intIdMaquina AND idArtigo IN (:idArtigo)";
    const viewFieldsStockMaquina =
      "[intIdMaq], idArtigo, [intPosicao], [stringNome], [strTamanho], idTamanho, idTamanhoArtigo, [Qtd], stringCaminhoImagem";
    const queryParamsStockMaquina = {
      intIdMaquina: maquinaId,
      idArtigo: intIdArtigoArrayReturn,
    };

    const resultStockMaquina =
      await customQuery.executeDynamicQueryWithWhereAndGroupBy(
        viewNameStockMaquina,
        whereClauseStockMaquina,
        viewFieldsStockMaquina,
        undefined,
        queryParamsStockMaquina
      );

    //Valida Qtd Disponivel por Dia
    const viewNameQtdDisponivelDia = "[dbo].[view_Front_QtdUtilizadaDia]";
    const whereClauseQtdDisponivelDia =
      "intIdUser = :idUser AND Ano = :ano AND Mes = :mes AND dia = :dia";
    const viewFieldsQtdDisponivelDia =
      "[intIdUser], [Ano], [Mes], [dia], [intIdArtigo], [QtdUtilizadaDia] * -1 as QtdUtilizadaDia";
    const queryParamsQtdDisponivelDia = {
      idUser: userId,
      ano: anoAtual,
      mes: mesAtual,
      dia: diaAtual,
    };

    const resultQtdDisponivelDia =
      await customQuery.executeDynamicQueryWithWhereAndGroupBy(
        viewNameQtdDisponivelDia,
        whereClauseQtdDisponivelDia,
        viewFieldsQtdDisponivelDia,
        undefined,
        queryParamsQtdDisponivelDia
      );

    //console.log(returnArray);
    const concatenatedArray = await Promise.all(
      returnArray.map(async (item) => {
        const matchingStockMaquina = resultStockMaquina.filter(
          (stockItem) => stockItem.idArtigo === item.intIdArtigo
        );
        const matchingQtdDisponivelDia = resultQtdDisponivelDia.filter(
          (qtdItem) => qtdItem.intIdArtigo === item.intIdArtigo
        );
        //const caminhoImagem = matchingQtdDisponivelDia ? matchingQtdDisponivelDia.stringCaminhoImagem : null;
        // Extracting unique idTamanhos
        // console.log(matchingStockMaquina);
        const uniqueIdTamanhos = [
          ...new Set(
            matchingStockMaquina.map((stockItem) => stockItem.idTamanho)
          ),
        ];

        // Mapping StockMaquina items to { intPosicao, strTamanho, idTamanho, Qtd, stringNome } for each unique idTamanho

        const stockMaquinaData = uniqueIdTamanhos
          .map((idTamanho) => {
            const matchingStockItems = matchingStockMaquina.filter(
              (stockItem) => stockItem.idTamanho === idTamanho
            );
            // console.log(matchingStockItems);
            const stockItemWithQtd = matchingStockItems.find(
              (stockItem) => parseInt(stockItem.Qtd) > 0
            );

            return {
              intPosicao: stockItemWithQtd ? stockItemWithQtd.intPosicao : null,
              strTamanho: stockItemWithQtd
                ? parseInt(stockItemWithQtd.strTamanho)
                : null,
              idTamanho: idTamanho,
              idTamanhoArtigo: stockItemWithQtd
                ? parseInt(stockItemWithQtd.idTamanhoArtigo)
                : null,
              Qtd: stockItemWithQtd ? stockItemWithQtd.Qtd : null,
              //stringNome: stockItemWithQtd ? stockItemWithQtd.stringNome : null
            };
          })
          .filter((item) => item.intPosicao !== null);

        // Sort stockMaquinaData by strTamanho ascending
        stockMaquinaData.sort((a, b) => a.strTamanho - b.strTamanho);

        // Finding QtdUtilizadaDia
        const qtdUtilizadaDia =
          matchingQtdDisponivelDia.find(
            (qtdItem) => qtdItem.intIdArtigo === item.intIdArtigo
          )?.QtdUtilizadaDia || 0;

        //Validar, caso o artigo requeira devolução, deve validar se o artigo está disponivel ou precisa de ser devolvido.
        // Calculating isDisponivel

        const requerJustificao = result1_1.find(
          (result1_1) => result1_1.intIdArtigo === item.intIdArtigo
        ).bitRequerJustificacao;

        let arrayJustificacoes = [];
        if (requerJustificao) {
          arrayJustificacoes = resultJustificacoes;
        }

        let idLinhaDevolucao = 0;
        const requerDevolucao = result1_1.find(
          (result1_1) => result1_1.intIdArtigo === item.intIdArtigo
        ).bitRequerDevolucao;
        let isInUse = false;
        if (requerDevolucao) {
          const funcResponse = await checkIfArtigoIsInUse(
            userId,
            item.intIdArtigo
          );

          idLinhaDevolucao = funcResponse.idLinhaDevolucao;
          isInUse = funcResponse.isInUse;
        }

        const isDisponivel =
          stockMaquinaData.some((stockItem) => stockItem.Qtd > 0) &&
          item.intQtdMaxDia - qtdUtilizadaDia > 0 &&
          item.intQtdMax - item.qtdLevantada > 0 &&
          !isInUse;

        // Checking for isTamanhoUnico
        const isTamanhoUnico = stockMaquinaData.some(
          (stockItem) => stockItem.idTamanho === "1"
        );

        // Finding nomeArtigo from resultNomeArtigos

        const nomeArtigo =
          resultNomeArtigos.find(
            (nomeItem) => nomeItem.intId === item.intIdArtigo
          )?.stringNome || null;
        const imagem =
          resultNomeArtigos.find(
            (nomeItem) => nomeItem.intId === item.intIdArtigo
          )?.stringCaminhoImagem || null;

        // Creating the final object
        return {
          idArtigo: item.intIdArtigo,
          nomeArtigo: nomeArtigo,
          qtdMax: item.intQtdMax,
          qtdLevantada: item.qtdLevantada,
          qtdMaxDia: item.intQtdMaxDia,
          qtdUtilizadaDia: qtdUtilizadaDia,
          stockMaquina: stockMaquinaData,
          isDisponivel: isDisponivel,
          isTamanhoUnico: isTamanhoUnico,
          caminhoImagem: imagem, // caminhoImagem from resultNomeArtigos
          requerJustificacao: requerJustificao,
          requerDevolucao: requerDevolucao,
          isInUse: isInUse,
          idLinhaDevolucao: idLinhaDevolucao,
          justificacoes: arrayJustificacoes,
        };
      })
    );

    const sortedArray = concatenatedArray.sort((a, b) => {
      // Compare the isDisponivel property
      if (a.isDisponivel && !b.isDisponivel) {
        return -1; // a comes before b
      } else if (!a.isDisponivel && b.isDisponivel) {
        return 1; // b comes before a
      } else {
        return 0; // no change in order
      }
    });
    return sortedArray;

    // Now return the modified returnArray
  } catch (error) {
    console.error("Error in getArtigosPorUtilizadorDashboard:", error);
    throw error;
  }
};

const checkIfArtigoIsInUse = async (idUser, idArtigo) => {
  const viewNameQtdDisponivelDia = "[dbo].[view_Front_ArtigosEmUso]";
  const whereClauseQtdDisponivelDia =
    "intIdUser = :idUser AND intIdArtigo = :idArtigo ORDER BY intId DESC";
  const viewFieldsQtdDisponivelDia = "[bitIsDevolvido], [intId]";
  const queryParamsQtdDisponivelDia = {
    idUser: idUser,
    idArtigo: idArtigo,
  };

  const resultQtdDisponivelDia =
    await customQuery.executeDynamicQueryWithWhereAndGroupBy(
      viewNameQtdDisponivelDia,
      whereClauseQtdDisponivelDia,
      viewFieldsQtdDisponivelDia,
      undefined,
      queryParamsQtdDisponivelDia
    );
  if (resultQtdDisponivelDia.length <= 0) {
    return { isInUse: false, idLinhaDevolucao: null };
  }
  if (resultQtdDisponivelDia[0].bitIsDevolvido) {
    return { isInUse: false, idLinhaDevolucao: null };
  } else {
    const idLinhaDevolucao = resultQtdDisponivelDia[0].intId;
    return { isInUse: true, idLinhaDevolucao: idLinhaDevolucao };
  }
};

const getCurrentMonthNumber = () => {
  const currentDate = new Date();
  const currentMonth = currentDate.getMonth() + 1; // Adding 1 to get the month number starting from 1 for January
  return currentMonth;
};

const getCurrentYear = () => {
  const currentDate = new Date();
  const currentYear = currentDate.getFullYear();
  return currentYear;
};

const getCurrentDay = () => {
  const currentDate = new Date();
  return currentDate.getDate();
};

const addMonthsIncrementally = (
  startMonth,
  startYear,
  currentMonth,
  currentYear,
  monthsToAdd,
  isMensal
) => {
  let newMonth = startMonth;
  let newYear = startYear;
  let previousNewMonth;
  let previousNewYear;

  while (
    newYear <= currentYear ||
    (newYear === currentYear && newMonth <= currentMonth)
  ) {
    previousNewMonth = newMonth;
    previousNewYear = newYear;

    newMonth += monthsToAdd;

    if (newMonth > 12) {
      newMonth -= 12;
      newYear++;
    }
    // console.log("newMonth: "+ newMonth + "   newYear: "+ newYear);
    // Exit the loop if newMonth is greater than currentMonth
    if (newMonth > currentMonth && newYear >= currentYear) {
      break;
    }
  }

  if (isMensal) {
    return {
      previousNewMonth,
      previousNewYear,
      previousNewMonth,
      previousNewYear,
    };
  }

  return { newMonth, newYear, previousNewMonth, previousNewYear };
};

module.exports = {
  getDashboardData,
};
