import InputSelectComponent from "@/components/Forms/InputSelect";
import {
  CAMPO_MODELO_POR_CANAL,
  opcoesModelosPorTipo,
  opcoesTipoNotificacao,
  paraListaDeCanais,
} from "@/constants/modeloNotificacao";
import {
  Desc_TipoNotifEmail,
  Desc_TipoNotificacaoCanal,
  TipoNotifEmail,
  TipoNotificacaoCanal,
  getOptionsFromEnum,
} from "@/enums/enums";
import { testarNotificacaoNegocioParado } from "@/requests/CRM/kanban";
import { listarUsuario } from "@/requests/CRM/agenda";
import { listarModeloEmail } from "@/requests/CRUD/ModelosEmail/listarModeloEmail";
import { useAuth } from "@/src/contexts/authContext";
import { useEffect, useState } from "react";

interface Mail {
  id: number;
  etapa_id: number;
  modelo_email_id: number | null;
  modelo_whatsapp_id: number | null;
  modelo_central_id: number | null;
  modelo_email_assunto: string;
  enviar_email: number;
  email_personalizado: string | null;
  // CSV de id_usuario da Lista Personalizada (item 04)
  usuarios_personalizados: string | null;
  // Lista CSV: pode notificar pelos 3 tipos ao mesmo tempo.
  tipo_notificacao_canal: string;
}

/** Configuração da notificação de "negócio parado", independente das demais. */
export interface ParadoNotificacao {
  papeis: string[];
  canais: string[];
  modelo_email_id: number | null;
  modelo_whatsapp_id: number | null;
  modelo_central_id: number | null;
  email_personalizado: string | null;
  usuarios_personalizados: string | null;
}

const Secao = ({ titulo, descricao, children }: any) => (
  <section className="mb-4 rounded-md border border-stroke p-4 dark:border-strokedark">
    <p className="text-sm font-semibold uppercase tracking-wide text-black-2/70 dark:text-white/70">
      {titulo}
    </p>
    {descricao && (
      <p className="mt-0.5 text-xs text-black-2/50 dark:text-white/50">
        {descricao}
      </p>
    )}
    <div className="mt-3">{children}</div>
  </section>
);

/**
 * Tipo de notificação (aceita mais de um) + o Modelo de Notificação de cada
 * tipo escolhido. Usado tanto pela notificação de entrada na etapa quanto pela
 * de negócio parado (item 05 e item 06).
 */
const CanaisEModelos = ({
  canais,
  modelos,
  modelosDoCanal,
  onToggleCanal,
  onChangeModelo,
  idPrefixo,
}: {
  canais: string[];
  modelos: Record<string, any>;
  modelosDoCanal: (canal: string) => { value: any; label: string }[];
  onToggleCanal: (canal: string) => void;
  onChangeModelo: (canal: string, idModelo: any) => void;
  idPrefixo: string;
}) => (
  <div className="flex flex-col gap-3">
    <div className="flex flex-col gap-1">
      <span className="text-xs font-semibold uppercase tracking-wide text-black-2/60 dark:text-white/60">
        Tipo de Notificação
      </span>
      <div className="flex flex-row flex-wrap items-center gap-4">
        {opcoesTipoNotificacao.map((opcao) => (
          <label
            key={opcao.value}
            className="flex cursor-pointer flex-row items-center gap-1"
          >
            <input
              type="checkbox"
              checked={canais.includes(opcao.value)}
              onChange={() => onToggleCanal(opcao.value)}
            />
            <span>{opcao.label}</span>
          </label>
        ))}
      </div>
    </div>

    {canais.length === 0 ? (
      <span className="text-sm text-danger">
        Selecione ao menos um Tipo de Notificação.
      </span>
    ) : (
      <div className="grid grid-cols-1 gap-3 xl:grid-cols-3">
        {canais.map((canal) => {
          const opcoesModelo = modelosDoCanal(canal);
          const nomeCanal = (Desc_TipoNotificacaoCanal as any)[canal];

          if (opcoesModelo.length === 0) {
            return (
              <div key={canal} className="flex flex-col gap-1">
                <span className="labelInputDynamic text-black dark:text-white">
                  Modelo de {nomeCanal}
                </span>
                <span className="text-sm text-danger">
                  Nenhum Modelo de Notificação ativo do tipo {nomeCanal}.
                  Cadastre um em Configurações Gerais {">"} Modelo de
                  Notificações.
                </span>
              </div>
            );
          }

          return (
            <InputSelectComponent
              key={`${idPrefixo}-${canal}`}
              name={`${idPrefixo}_${CAMPO_MODELO_POR_CANAL[canal]}`}
              label={`Modelo de ${nomeCanal}`}
              options={opcoesModelo}
              controlledValue={modelos[canal]?.toString() ?? ""}
              onChange={(opcao: any) =>
                onChangeModelo(canal, opcao?.value ?? null)
              }
            />
          );
        })}
      </div>
    )}
  </div>
);

/**
 * Item 04: campos da opção "Notificar uma Lista Personalizada". Ficam sempre
 * por último, depois do Tipo de Notificação e dos Modelos. Além dos e-mails, a
 * lista aceita usuários do sistema — é assim que se notifica pela Central de
 * Notificações / WhatsApp quem não é Vendedor, Pré-Vendedor, Técnico, Gerente
 * ou Instalador do negócio.
 */
const CamposListaPersonalizada = ({
  idPrefixo,
  usuarios,
  usuariosSelecionados,
  emails,
  onChangeUsuarios,
  onChangeEmails,
}: {
  idPrefixo: string;
  usuarios: any[];
  usuariosSelecionados: string | null;
  emails: string | null;
  onChangeUsuarios: (csv: string | null) => void;
  onChangeEmails: (valor: string) => void;
}) => (
  <div className="flex flex-col gap-3 border-t border-stroke pt-3 dark:border-strokedark">
    <InputSelectComponent
      name={`${idPrefixo}_usuarios_personalizados`}
      label="Usuários da lista personalizada"
      isMulti
      options={usuarios.map((usuario: any) => ({
        value: String(usuario.id_usuario),
        label: usuario.nome_usuario,
      }))}
      controlledValue={usuariosSelecionados ?? ""}
      onChange={(selecionados: any) =>
        onChangeUsuarios(paraListaDeCanais(selecionados).join(",") || null)
      }
    />
    <span className="-mt-2 text-xs text-primary">
      Notificados pela Central de Notificações e pelo WhatsApp, além dos
      responsáveis do negócio.
    </span>

    <div className="flex flex-col gap-1">
      <label
        htmlFor={`emailDestino_${idPrefixo}`}
        className="text-xs font-semibold uppercase tracking-wide text-black-2/60 dark:text-white/60"
      >
        E-mails da lista personalizada
      </label>
      <input
        id={`emailDestino_${idPrefixo}`}
        type="text"
        value={emails ?? ""}
        placeholder="fulano@empresa.com, ciclano@empresa.com"
        onChange={(e) => onChangeEmails(e.target.value)}
        className="w-full rounded border bg-transparent p-2"
      />
      <span className="text-xs text-primary">
        Separe com vírgula caso tenha mais de um e-mail.
      </span>
    </div>
  </div>
);

const ConfiguracoesNotificacoesEtapa = ({
  id_etapa_funil,
  notificacoesEmail,
  setNotificacoesEmail,
  diasParadoNotificacao,
  setDiasParadoNotificacao,
  paradoNotificacao,
  setParadoNotificacao,
}: any) => {
  const [modelosNotificacao, setModelosNotificacao] = useState<any[]>([]);
  const [usuarios, setUsuarios] = useState<any[]>([]);
  const [testandoParado, setTestandoParado] = useState(false);
  const { valuesSession } = useAuth();
  const { session } = valuesSession();

  useEffect(() => {
    listarModeloEmail().then(setModelosNotificacao);
    listarUsuario().then((res: any) => setUsuarios(res ?? []));
  }, []);

  const emailOptions = getOptionsFromEnum(TipoNotifEmail, Desc_TipoNotifEmail);


  const modelosDoCanal = (canal: string) =>
    opcoesModelosPorTipo(modelosNotificacao, canal);

  const linhaVazia = (id: number): Mail => ({
    id,
    etapa_id: id_etapa_funil,
    enviar_email: 0,
    modelo_email_id: null,
    modelo_whatsapp_id: null,
    modelo_central_id: null,
    modelo_email_assunto: "",
    email_personalizado: null,
    usuarios_personalizados: null,
    tipo_notificacao_canal: TipoNotificacaoCanal.Email,
  });

  // Garante uma linha por destinatário — inclusive os papéis criados depois que
  // a etapa já havia sido salva (ex.: Instalador).
  useEffect(() => {
    const linhasAtuais: Mail[] = Array.isArray(notificacoesEmail)
      ? notificacoesEmail
      : [];

    const faltantes = emailOptions
      .filter(
        (option) =>
          !linhasAtuais.some(
            (linha) => linha.id?.toString() === option.value.toString()
          )
      )
      .map((option) => linhaVazia(parseInt(option.value)));

    if (faltantes.length > 0) {
      setNotificacoesEmail([...linhasAtuais, ...faltantes]);
    }
    // As demais dependências são recriadas a cada render: incluí-las faria o
    // efeito rodar em laço.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [notificacoesEmail]);

  const atualizarLinha = (id: number, alteracoes: Partial<Mail>) =>
    setNotificacoesEmail((prevState: any) =>
      (prevState ?? []).map((linha: Mail) =>
        linha.id === id ? { ...linha, ...alteracoes } : linha
      )
    );

  const alternarDestinatario = (linha: Mail) => {
    const passouAMarcar = linha.enviar_email != 1;

    atualizarLinha(linha.id, {
      enviar_email: passouAMarcar ? 1 : 0,
      // Ao marcar, já entra com E-mail sugerido para o Integrador só escolher o modelo.
      tipo_notificacao_canal:
        passouAMarcar && !linha.tipo_notificacao_canal
          ? TipoNotificacaoCanal.Email
          : linha.tipo_notificacao_canal,
    });
  };

  const alternarCanalDaLinha = (linha: Mail, canal: string) => {
    const canaisAtuais = paraListaDeCanais(linha.tipo_notificacao_canal);
    const canaisNovos = canaisAtuais.includes(canal)
      ? canaisAtuais.filter((atual) => atual !== canal)
      : [...canaisAtuais, canal];

    atualizarLinha(linha.id, {
      tipo_notificacao_canal: canaisNovos.join(","),
      // Descartar o modelo do tipo que deixou de ser notificado
      [CAMPO_MODELO_POR_CANAL[canal]]: canaisNovos.includes(canal)
        ? (linha as any)[CAMPO_MODELO_POR_CANAL[canal]]
        : null,
    } as Partial<Mail>);
  };

  const definirModeloDaLinha = (linha: Mail, canal: string, idModelo: any) => {
    const alteracoes: Partial<Mail> = {
      [CAMPO_MODELO_POR_CANAL[canal]]: idModelo,
    } as Partial<Mail>;

    // O assunto do e-mail é copiado do modelo, como o envio espera.
    if (canal === TipoNotificacaoCanal.Email) {
      alteracoes.modelo_email_assunto =
        modelosNotificacao.find((modelo) => modelo.id == idModelo)?.assunto ||
        "";
    }

    atualizarLinha(linha.id, alteracoes);
  };

  // ===== Notificação de negócio parado (independente das demais) =====
  const parado: ParadoNotificacao = {
    papeis: [],
    canais: [],
    modelo_email_id: null,
    modelo_whatsapp_id: null,
    modelo_central_id: null,
    email_personalizado: null,
    usuarios_personalizados: null,
    ...(paradoNotificacao ?? {}),
  };

  const notificaParado = Number(diasParadoNotificacao) > 0;

  const atualizarParado = (alteracoes: Partial<ParadoNotificacao>) =>
    setParadoNotificacao?.({ ...parado, ...alteracoes });

  const alternarPapelParado = (papel: string) =>
    atualizarParado({
      papeis: parado.papeis.includes(papel)
        ? parado.papeis.filter((atual) => atual !== papel)
        : [...parado.papeis, papel],
    });

  const alternarCanalParado = (canal: string) => {
    const canaisNovos = parado.canais.includes(canal)
      ? parado.canais.filter((atual) => atual !== canal)
      : [...parado.canais, canal];

    atualizarParado({
      canais: canaisNovos,
      [CAMPO_MODELO_POR_CANAL[canal]]: canaisNovos.includes(canal)
        ? (parado as any)[CAMPO_MODELO_POR_CANAL[canal]]
        : null,
    } as Partial<ParadoNotificacao>);
  };

  const modelosDoParado: Record<string, any> = {
    [TipoNotificacaoCanal.Email]: parado.modelo_email_id,
    [TipoNotificacaoCanal.WhatsApp]: parado.modelo_whatsapp_id,
    [TipoNotificacaoCanal.Central]: parado.modelo_central_id,
  };

  // Dispara o teste com o que está na tela (sem depender de salvar a etapa).
  // Quem recebe é só o usuário logado — nenhum responsável do negócio é avisado.
  const dispararTesteParado = async () => {
    setTestandoParado(true);

    try {
      await testarNotificacaoNegocioParado({
        id_etapa_funil,
        id_usuario: session?.id_usuario,
        dias_parado_notificacao: diasParadoNotificacao,
        canais: parado.canais.join(","),
        modelo_email_id: parado.modelo_email_id,
        modelo_whatsapp_id: parado.modelo_whatsapp_id,
        modelo_central_id: parado.modelo_central_id,
      });
    } catch (erro) {
      // O erro já é exibido pelo toast da requisição.
      console.error("Falha ao disparar o teste de negócio parado:", erro);
    } finally {
      setTestandoParado(false);
    }
  };

  const rotuloDestinatario = (option: { value: string; label: string }) =>
    option.value === TipoNotifEmail.Personalizado ? (
      <>
        Notificar uma <span className="font-bold">Lista Personalizada</span>
      </>
    ) : (
      <>
        Notificar o{" "}
        <span className="font-bold uppercase">{option.label}</span> do Negócio
      </>
    );

  return (
    <div className="flex 2xl:flex-row flex-col gap-8">
      {/* Item 05: primeiro quem será notificado; o tipo e o modelo só aparecem
          para os destinatários marcados. */}
      <Secao
        titulo="Entrada do Card nesta Etapa"
        descricao="Marque quem deve ser notificado quando o negócio entrar nesta etapa e escolha o tipo e o modelo da notificação."
      >
        <div className="flex flex-col gap-2">
          {emailOptions.map((option) => {
            const linha: Mail | undefined = (notificacoesEmail ?? []).find(
              (email: Mail) => email.id?.toString() === option.value.toString()
            );

            if (!linha) return null;

            const marcado = linha.enviar_email == 1;
            const canaisDaLinha = paraListaDeCanais(
              linha.tipo_notificacao_canal
            );
            const modelosDaLinha: Record<string, any> = {
              [TipoNotificacaoCanal.Email]: linha.modelo_email_id,
              [TipoNotificacaoCanal.WhatsApp]: linha.modelo_whatsapp_id,
              [TipoNotificacaoCanal.Central]: linha.modelo_central_id,
            };

            return (
              <div
                key={option.value}
                className={`rounded-md border p-3 transition-colors ${marcado
                  ? "border-primary/40 bg-primary/5"
                  : "border-stroke dark:border-strokedark"
                  }`}
              >
                <label className="flex cursor-pointer flex-row items-center gap-2">
                  <input
                    type="checkbox"
                    checked={marcado}
                    onChange={() => alternarDestinatario(linha)}
                  />
                  <span>{rotuloDestinatario(option)}</span>
                </label>

                {marcado && (
                  <div className="mt-3 flex flex-col gap-3 border-t border-stroke pt-3 dark:border-strokedark">
                    <CanaisEModelos
                      idPrefixo={`etapa_${linha.id}`}
                      canais={canaisDaLinha}
                      modelos={modelosDaLinha}
                      modelosDoCanal={modelosDoCanal}
                      onToggleCanal={(canal) =>
                        alternarCanalDaLinha(linha, canal)
                      }
                      onChangeModelo={(canal, idModelo) =>
                        definirModeloDaLinha(linha, canal, idModelo)
                      }
                    />

                    {option.value === TipoNotifEmail.Personalizado && (
                      <CamposListaPersonalizada
                        idPrefixo={`etapa_${linha.id}`}
                        usuarios={usuarios}
                        usuariosSelecionados={linha.usuarios_personalizados}
                        emails={linha.email_personalizado}
                        onChangeUsuarios={(csv) =>
                          atualizarLinha(linha.id, {
                            usuarios_personalizados: csv,
                          })
                        }
                        onChangeEmails={(valor) =>
                          atualizarLinha(linha.id, {
                            email_personalizado: valor,
                          })
                        }
                      />
                    )}
                  </div>
                )}
              </div>
            );
          })}
        </div>
      </Secao>

      {/* Item 06: a notificação de negócio parado tem destinatários, tipo e
          modelo próprios — não reaproveita os da entrada na etapa. */}
      <Secao
        titulo="Negócio Parado nesta Etapa"
        descricao="Configuração independente da notificação de entrada: aqui você escolhe quem é avisado quando o negócio trava nesta etapa."
      >
        <div className="flex flex-col gap-3">
          {/* A varredura é feita pelo cron do servidor, não no momento em que a
              etapa é salva — deixar isso claro evita a dúvida de "configurei e
              não recebi nada agora". */}
          <p className="rounded-md border-l-4 border-warning bg-warning/10 p-3 text-sm font-bold uppercase text-black-2 dark:text-white">
            ATENÇÃO!! Esta verificação é feita no servidor todos os dias a
            noites e notificado os responsáveis quando setado para notificar!
          </p>

          <div className="flex flex-row flex-wrap items-center gap-2">
            <label htmlFor="diasParadoNotificacao">
              Notificar se o negócio ficar parado nesta etapa por:
            </label>
            <input
              id="diasParadoNotificacao"
              type="number"
              min={0}
              className="w-20 rounded border bg-transparent px-2 py-1"
              value={diasParadoNotificacao ?? ""}
              onChange={(e) =>
                setDiasParadoNotificacao?.(
                  e.target.value ? Number(e.target.value) : null
                )
              }
            />
            <span>dias (deixe em branco para não notificar)</span>
          </div>

          {notificaParado && (
            <div className="flex flex-col gap-3 border-t border-stroke pt-3 dark:border-strokedark">
              <div className="flex flex-col gap-1">
                <span className="text-xs font-semibold uppercase tracking-wide text-black-2/60 dark:text-white/60">
                  Quem será notificado
                </span>
                <div className="grid grid-cols-1 gap-2 sm:grid-cols-2 xl:grid-cols-3">
                  {emailOptions.map((option) => (
                    <label
                      key={option.value}
                      className="flex cursor-pointer flex-row items-center gap-2"
                    >
                      <input
                        type="checkbox"
                        checked={parado.papeis.includes(option.value)}
                        onChange={() => alternarPapelParado(option.value)}
                      />
                      <span>{rotuloDestinatario(option)}</span>
                    </label>
                  ))}
                </div>
                {parado.papeis.length === 0 && (
                  <span className="text-sm text-danger">
                    Informe quem será notificado quando o negócio ficar parado.
                  </span>
                )}
              </div>

              <CanaisEModelos
                idPrefixo="parado"
                canais={parado.canais}
                modelos={modelosDoParado}
                modelosDoCanal={modelosDoCanal}
                onToggleCanal={alternarCanalParado}
                onChangeModelo={(canal, idModelo) =>
                  atualizarParado({
                    [CAMPO_MODELO_POR_CANAL[canal]]: idModelo,
                  } as Partial<ParadoNotificacao>)
                }
              />

              {parado.papeis.includes(TipoNotifEmail.Personalizado) && (
                <CamposListaPersonalizada
                  idPrefixo="parado"
                  usuarios={usuarios}
                  usuariosSelecionados={parado.usuarios_personalizados}
                  emails={parado.email_personalizado}
                  onChangeUsuarios={(csv) =>
                    atualizarParado({ usuarios_personalizados: csv })
                  }
                  onChangeEmails={(valor) =>
                    atualizarParado({ email_personalizado: valor })
                  }
                />
              )}

              {/* Teste do modelo configurado: usa o que está na tela, sem
                  esperar a varredura da noite, e só notifica quem pediu. */}
              <div className="flex flex-col gap-1 border-t border-stroke pt-3 dark:border-strokedark">
                <button
                  type="button"
                  disabled={
                    testandoParado ||
                    parado.canais.length === 0 ||
                    !id_etapa_funil
                  }
                  onClick={dispararTesteParado}
                  className="w-fit rounded bg-primary px-4 py-2 text-white disabled:cursor-not-allowed disabled:opacity-50"
                >
                  {testandoParado
                    ? "Enviando teste..."
                    : "Disparar teste do modelo configurado"}
                </button>
                <span className="text-xs text-primary">
                  {!id_etapa_funil
                    ? "Salve a etapa para poder disparar o teste."
                    : "O teste usa os modelos selecionados acima e é enviado somente para você, sem notificar os responsáveis do negócio."}
                </span>
              </div>
            </div>
          )}
        </div>
      </Secao>
    </div>
  );
};

export default ConfiguracoesNotificacoesEtapa;
