import { listarRelacionamenosRapidos } from "@/requests/common/RelacionamentosRapidos/listarRelacionamenosRapidos";
import { listarCamposPersonalizadosRelacionamentos } from "@/requests/CRUD/CamposPersonalizados/listarCamposPersonalizados";
import { calcularParcela, formatarValor, FormatFields } from "@/utils";
import { splitBase64 } from "@/utils/pdfme/helper";
import { cloneDeep, Template } from "@pdfme/common";
import { times } from "lodash";
import { usePathname } from "next/navigation";
import { PDFDocument } from "pdf-lib";
import {
  createContext,
  ReactNode,
  useContext,
  useEffect,
  useState,
} from "react";
import { useContractContext } from "./ContractProvider";

interface IProviderProps {
  children: ReactNode;
}

interface IProposalProviderData {
  relacionamentosProposta: {
    name: string;
    text: string;
    relacionamento: any;
    grupo_relacionamento_rapido?: any;
  }[];
  camposRelacionamentosProposta: {
    name: string;
    text: string;
    relacionamento: any;
    grupo_relacionamento_rapido?: any;
  }[];
  camposPersonalizadosRelacionamentosProposta: {
    name: string;
    text: string;
    relacionamento: any;
    grupo_relacionamento_rapido?: any;
  }[];
  getRelacionamentosRapidos: () => void;
  relacionarDadosProposta: (
    template: Template,
    dadosProposta: any
  ) => Promise<Template>;
  relacionarDadosPropostaELB: (
    template: Template,
    dadosProposta: any
  ) => Promise<Template>;
}

const ProposalContext = createContext({} as IProposalProviderData);

const currencyColumns = new Set([
  "preco_tarifa",
  "tarifa_energia",
  "tarifa_energia_evitada",
  "receita_energia",
  "receita_energia_evitada",
  "tarifa_scee",
  "receita_scee",
  "receita_bruta",
  "opex",
  "seguro",
  "receita_liquida",
  "fluxo_caixa",
  "economia_gerada",
  "resultado_financeiro",
  "cdb_130",
  "cdi",
  "poupanca",
]);

const toNumber = (value: any) => {
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : 0;
};

const getHeaders = (schema: any): string[] => {
  if (!schema?.content) return [];
  try {
    const parsed = JSON.parse(schema.content);
    return Array.isArray(parsed?.[0]) ? parsed[0] : [];
  } catch {
    return [];
  }
};

const formatCell = (key: string, value: any) => {
  if (value === undefined || value === null) return "";
  if (currencyColumns.has(key)) return formatarValor(toNumber(value));
  if (typeof value === "number") return String(value.toFixed(0));
  return String(value);
};

const mapRows = (
  rows: any[] = [],
  headers: string[] = [],
  keyMap: Record<string, string> = {}
) =>
  rows.map((row) =>
    headers.map((header) =>
      formatCell(keyMap[header] ?? header, row?.[keyMap[header] ?? header])
    )
  );

const mergeArraysByIndexFlexible = <T,>(
  ...arrays: T[][]
): (T | undefined)[][] => {
  const maxLength = Math.max(...arrays.map((arr) => arr.length));
  return Array.from({ length: maxLength }, (_, index) =>
    arrays.map((arr) => arr[index])
  );
};

const setReplacement = (schema: any, placeholder: string, value: any) => {
  const replacement = String(value ?? "");
  if (typeof schema.content === "string") {
    schema.content = schema.content.replaceAll(placeholder, replacement);
  }
  if (Array.isArray(schema.head)) {
    schema.head = schema.head.map((head: string) =>
      head.replaceAll(placeholder, replacement)
    );
  }
};

export const ProposalProvider = ({ children }: IProviderProps) => {
  const pathname = usePathname() as any;
  const { relacionamentosContrato } = useContractContext();

  const [relacionamentosProposta, setRelacionamentosProposta] = useState<any[]>(
    []
  );
  const [camposRelacionamentosProposta, setCamposRelacionamentosProposta] =
    useState<any[]>([]);
  const [
    camposPersonalizadosRelacionamentosProposta,
    setCamposPersonalizadosRelacionamentosProposta,
  ] = useState<any[]>([]);

  const meses = [
    "Janeiro",
    "Fevereiro",
    "Março",
    "Abril",
    "Maio",
    "Junho",
    "Julho",
    "Agosto",
    "Setembro",
    "Outubro",
    "Novembro",
    "Dezembro",
    "Média",
  ];

  const mesesSigla = [
    "JAN",
    "FEV",
    "MAR",
    "ABR",
    "MAI",
    "JUN",
    "JUL",
    "AGO",
    "SET",
    "OUT",
    "NOV",
    "DEZ",
    "MÉD",
  ];

  const getRelacionamentosRapidos = () => {
    if (pathname === "/") return;

    Promise.all([
      listarRelacionamenosRapidos(),
      listarCamposPersonalizadosRelacionamentos(),
    ]).then(([relacionamentos, camposPersonalizados]) => {
      const relacionamentosFiltrados = relacionamentos
        .filter(
          (e: any) =>
            e.status_relacionamento_rapido == 1 &&
            e.mostrarProposta_relacionamento_rapido == 1
        )
        .map((rel: any) => ({
          name: rel.nome_relacionamento_rapido,
          text:
            rel.text_relacionamento_rapido || rel.nome_relacionamento_rapido,
          relacionamento: rel.nome_relacionamento_rapido,
          grupo_relacionamento_rapido: rel.grupo_relacionamento_rapido,
          colunas_tabela: rel.colunas_tabela_relacionamento_rapido,
        }));

      const personalizados = camposPersonalizados.map((campo: any) => ({
        name: campo.nome_relacionamento_rapido,
        text: campo.nome_campo_personalizado,
        relacionamento: campo.nome_relacionamento_rapido,
        local_campo_personalizado: campo.local_campo_personalizado,
      }));

      setRelacionamentosProposta([
        ...relacionamentosFiltrados,
        ...personalizados,
        ...(Array.isArray(relacionamentosContrato)
          ? relacionamentosContrato
          : []),
      ]);
      setCamposRelacionamentosProposta(relacionamentosFiltrados);
      setCamposPersonalizadosRelacionamentosProposta(personalizados);
    });
  };

  useEffect(() => {
    getRelacionamentosRapidos();
  }, [pathname]);

  const formatTabelaRsi = (tabelaValues: any[], schema: any) => {
    const headers = getHeaders(schema);
    const keyMap: Record<string, string> = {
      descricao_item: "name",
      qtd: "qtd_item",
    };
    return mapRows(tabelaValues, headers, keyMap);
  };

  const formatTabelaGenerica = (tabelaValues: any, schema: any) => {
    const headers = getHeaders(schema);
    return mapRows(tabelaValues, headers);
  };

  const formatTabelaGeracao = (tabelaValues: any) => {
    return mergeArraysByIndexFlexible(
      tabelaValues?.consumos || [],
      tabelaValues?.geracoes || [],
      meses,
      mesesSigla,
      tabelaValues?.consumos_instantaneos || [],
      tabelaValues?.energias_ingetadas || [],
      tabelaValues?.porcentagens_geracaoes || []
    );
  };

  async function relacionarDadosProposta(
    template: Template,
    dadosProposta: any
  ): Promise<Template> {
    const relacionamentosPermitidos = await listarRelacionamenosRapidos().then(
      (res) =>
        res
          .filter(
            (e: any) =>
              e.status_relacionamento_rapido == 1 &&
              e.mostrarProposta_relacionamento_rapido == 1
          )
          .map((e: any) => e.nome_relacionamento_rapido)
    );

    const camposPersonalizados =
      await listarCamposPersonalizadosRelacionamentos();
    const novosRelacionamentos = [
      ...relacionamentosProposta,
      ...camposPersonalizados.map((campo: any) => ({
        name: campo.nome_relacionamento_rapido,
        text: campo.nome_campo_personalizado,
        relacionamento: campo.nome_relacionamento_rapido,
      })),
    ];

    let nextTemplate: any = cloneDeep(template);
    const pdfBase64 = splitBase64(nextTemplate.basePdf);

    if (dadosProposta?.instituicao_financeira?.[0]?.value == "0") {
      const pdfDoc = await PDFDocument.load(
        Buffer.from(typeof pdfBase64 === "string" ? pdfBase64 : "", "base64")
      );

      if (!dadosProposta?.observacoes) {
        const paginaComTabelaFinanciamento = nextTemplate.schemas.findIndex(
          (pagina: any[]) =>
            pagina.some((schema) => schema.name === "{tabela_financiamento}")
        );

        if (paginaComTabelaFinanciamento !== -1) {
          pdfDoc.removePage(paginaComTabelaFinanciamento);
          nextTemplate.schemas.splice(paginaComTabelaFinanciamento, 1);
        }
      } else {
        const nomesParaRemover = [
          "p7.1 copy copy",
          "p7.2 copy copy",
          "p7.3",
          "{tabela_financiamento}",
          "Campo113 copy",
          ...Array.from({ length: 12 }, (_, i) => `Campo${68 + i} copy copy`),
        ];

        nextTemplate.schemas = nextTemplate.schemas.map((pagina: any[]) => {
          const novaPagina = pagina.filter(
            (schema) => !nomesParaRemover.includes(schema.name)
          );

          novaPagina.forEach((schema) => {
            if (schema.name === "p7.1 copy copy 2") {
              schema.position.x = 17.19;
              schema.position.y = 5.95;
            }
            if (schema.name === "p7.2 copy copy 2") {
              schema.position.x = 110.07;
              schema.position.y = 5.95;
            }
            if (schema.name === "Campo107 copy") {
              schema.position.y = 38.04;
            }
          });

          return novaPagina;
        });
      }

      const newPdf = await pdfDoc.save();
      const newPdfBase64 = Buffer.from(newPdf).toString("base64");
      nextTemplate = Object.assign(cloneDeep(nextTemplate), {
        basePdf: `data:application/pdf;base64,${newPdfBase64}`,
        schemas: nextTemplate.schemas,
      });
    }

    nextTemplate.schemas = nextTemplate.schemas
      .map((page: any) =>
        page
          .flatMap((schema: any) => {
            if (!schema?.name) return schema;

            const match = schema.name.match(/^\{(.+)\}$/);
            const placeholderKey = match?.[1];

            if (
              placeholderKey &&
              !relacionamentosPermitidos.includes(placeholderKey)
            ) {
              setReplacement(
                schema,
                `{${placeholderKey}}`,
                dadosProposta?.[placeholderKey] ?? ""
              );
              return schema;
            }

            const relacionamento = novosRelacionamentos.find(
              (rel) => rel.name === placeholderKey
            );

            if (!relacionamento) {
              if (placeholderKey) {
                setReplacement(
                  schema,
                  `{${placeholderKey}}`,
                  dadosProposta?.[placeholderKey] ?? ""
                );
              }
              return schema;
            }

            const dadoRelacional =
              dadosProposta?.[relacionamento.relacionamento] ??
              (relacionamento.name.includes("img")
                ? ""
                : relacionamento.relacionamento);

            if (
              schema.type === "image" &&
              relacionamento.name.includes("img")
            ) {
              schema.content = dadoRelacional;
              return schema;
            }

            if (
              schema.type === "table" &&
              relacionamento.name === "tabela_geracao_val"
            ) {
              const tabelaValues =
                dadosProposta?.[relacionamento.relacionamento];
              if (schema.content && tabelaValues) {
                schema.content = JSON.stringify(
                  formatTabelaGenerica(
                    {
                      consumos: tabelaValues.consumos,
                      geracoes: tabelaValues.geracoes,
                      meses,
                      mesesSigla,
                      consumos_instantaneos: tabelaValues.consumos_instantaneos,
                      energias_ingetadas: tabelaValues.energias_ingetadas,
                      porcentagens_geracaoes:
                        tabelaValues.porcentagens_geracaoes,
                    },
                    schema
                  )
                );
              }
              return schema;
            }

            if (
              schema.type === "table" &&
              relacionamento.name === "tabela_rsi_val"
            ) {
              const tabelaValues =
                dadosProposta?.[relacionamento.relacionamento] || [];
              if (schema.content) {
                schema.content = JSON.stringify(
                  formatTabelaRsi(tabelaValues, schema)
                );
              }
              return schema;
            }

            if (
              schema.type === "table" &&
              relacionamento.name === "componentes_tabela_kit_val"
            ) {
              const tabelaValues =
                dadosProposta?.[relacionamento.relacionamento] || [];
              if (schema.content) {
                const headers = getHeaders(schema);
                schema.content = JSON.stringify(
                  mapRows(tabelaValues, headers, {
                    descricao_item: "name",
                    qtd: "qtd_item",
                  })
                );
              }
              return schema;
            }

            if (
              schema.type === "table" &&
              [
                "tabela_ucs",
                "tabela_porcentagem_uc",
                "tabela_ubs",
                "tabela_orientacoes_val",
                "tabela_inversores_origem",
                "tabela_distribuicao_modulos",
                "tabela_economia",
                "tabela_geracao",
              ].includes(relacionamento.name)
            ) {
              const tabelaValues =
                dadosProposta?.[relacionamento.relacionamento];
              if (schema.content && Array.isArray(tabelaValues)) {
                schema.content = JSON.stringify(
                  formatTabelaGenerica(tabelaValues, schema)
                );
              }
              return schema;
            }

            if (
              schema.type === "table" &&
              relacionamento.name === "tabela_financiamento"
            ) {
              if (dadosProposta?.instituicao_financeira?.[0]?.value == "0") {
                return false;
              }

              const instituicoes = dadosProposta?.instituicao_financeira || [];
              if (!schema.content) return schema;

              return instituicoes.flatMap((instituicao: any, index: number) => {
                const isCPF =
                  dadosProposta?.cpfCnpj_cliente &&
                  dadosProposta.cpfCnpj_cliente.length < 14;
                const keysParcelas = isCPF
                  ? { parcelas: "parcelasPF_inst", juros: "jurosPF_inst" }
                  : { parcelas: "parcelasPJ_inst", juros: "jurosPJ_inst" };

                const totalParcelas = Math.max(
                  1,
                  Math.floor(+instituicao[keysParcelas.parcelas] / 12)
                );
                const resultados = times(totalParcelas, (indexParcela) => {
                  const mesesParcela = (indexParcela + 1) * 12;
                  return [
                    `Simulação ${mesesParcela}x`,
                    `${mesesParcela} meses`,
                    FormatFields.formatarMoeda(
                      calcularParcela(
                        +dadosProposta.resultadoPrecificacao.preco_venda,
                        +instituicao[keysParcelas.juros],
                        mesesParcela
                      ).toFixed(2)
                    ),
                  ];
                });

                return [
                  {
                    name: `label ${instituicao.label || index}`,
                    type: "text",
                    content: instituicao.label,
                    position: {
                      x:
                        instituicoes.length === 1
                          ? schema.position.x
                          : index * 90 + 20,
                      y: schema.position.y - 5,
                    },
                    width: schema.width,
                    height: 5,
                    alignment: "center",
                    fontSize: 10,
                    fontColor: "#ffffff",
                    backgroundColor: "#2980ba",
                    opacity: 1,
                    fontName: "Roboto",
                  },
                  {
                    ...schema,
                    name: `table ${instituicao.label || index}`,
                    position: {
                      x:
                        instituicoes.length === 1
                          ? schema.position.x
                          : index * 90 + 20,
                      y: schema.position.y,
                    },
                    content: JSON.stringify(resultados),
                  },
                ];
              });
            }

            if (schema.type === "table") {
              const tabelaValues =
                dadosProposta?.[relacionamento.relacionamento];
              if (schema.content && Array.isArray(tabelaValues)) {
                schema.content = JSON.stringify(
                  formatTabelaGenerica(tabelaValues, schema)
                );
              }
              return schema;
            }

            setReplacement(schema, `{${relacionamento.name}}`, dadoRelacional);
            return schema;
          })
          .filter(Boolean)
      )
      .filter(Boolean);

    return nextTemplate;
  }

  async function relacionarDadosPropostaELB(
    template: Template,
    dadosProposta: any
  ): Promise<Template> {
    return relacionarDadosProposta(template, dadosProposta);
  }

  return (
    <ProposalContext.Provider
      value={{
        getRelacionamentosRapidos,
        relacionamentosProposta,
        camposRelacionamentosProposta,
        camposPersonalizadosRelacionamentosProposta,
        relacionarDadosProposta,
        relacionarDadosPropostaELB,
      }}
    >
      {children}
    </ProposalContext.Provider>
  );
};

export const useProposalContext = () => useContext(ProposalContext);
