import { v } from "convex/values";
import { mutation, query, internalMutation } from "./_generated/server";
import { Doc, Id } from "./_generated/dataModel";
import type { QueryCtx, MutationCtx } from "./_generated/server";

// ========== HELPERS ==========

/**
 * Helper function para obter usuário autenticado (Better Auth ou Sessão)
 */
async function getUsuarioAutenticado(ctx: QueryCtx | MutationCtx) {
  // Tentar autenticação via Better Auth primeiro
  const identity = await ctx.auth.getUserIdentity();
  let usuarioAtual = null;

  if (identity && identity.email) {
    usuarioAtual = await ctx.db
      .query("usuarios")
      .withIndex("by_email", (q) => q.eq("email", identity.email!))
      .first();
  }

  // Se não encontrou via Better Auth, tentar via sessão
  if (!usuarioAtual) {
    const sessaoAtiva = await ctx.db
      .query("sessoes")
      .filter((q) => q.eq(q.field("ativo"), true))
      .first();

    if (sessaoAtiva) {
      usuarioAtual = await ctx.db.get(sessaoAtiva.usuarioId);
    }
  }

  return usuarioAtual;
}

// ========== MUTATIONS ==========

/**
 * Cria uma nova conversa (individual ou grupo)
 */
export const criarConversa = mutation({
  args: {
    tipo: v.union(v.literal("individual"), v.literal("grupo")),
    participantes: v.array(v.id("usuarios")),
    nome: v.optional(v.string()),
    avatar: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    // Validar participantes
    if (!args.participantes.includes(usuarioAtual._id)) {
      args.participantes.push(usuarioAtual._id);
    }

    // Se for conversa individual, verificar se já existe
    if (args.tipo === "individual" && args.participantes.length === 2) {
      const conversaExistente = await ctx.db
        .query("conversas")
        .filter((q) => q.eq(q.field("tipo"), "individual"))
        .collect();

      for (const conversa of conversaExistente) {
        if (
          conversa.participantes.length === 2 &&
          conversa.participantes.every((p) => args.participantes.includes(p))
        ) {
          return conversa._id;
        }
      }
    }

    // Criar nova conversa
    const conversaId = await ctx.db.insert("conversas", {
      tipo: args.tipo,
      nome: args.nome,
      avatar: args.avatar,
      participantes: args.participantes,
      criadoPor: usuarioAtual._id,
      criadoEm: Date.now(),
    });

    // Criar notificações para outros participantes
    if (args.tipo === "grupo") {
      for (const participanteId of args.participantes) {
        if (participanteId !== usuarioAtual._id) {
          await ctx.db.insert("notificacoes", {
            usuarioId: participanteId,
            tipo: "adicionado_grupo",
            conversaId,
            remetenteId: usuarioAtual._id,
            titulo: "Adicionado a grupo",
            descricao: `Você foi adicionado ao grupo "${args.nome || "Sem nome"}" por ${usuarioAtual.nome}`,
            lida: false,
            criadaEm: Date.now(),
          });
        }
      }
    }

    return conversaId;
  },
});

/**
 * Cria ou busca uma conversa individual com outro usuário
 */
export const criarOuBuscarConversaIndividual = mutation({
  args: {
    outroUsuarioId: v.id("usuarios"),
  },
  returns: v.id("conversas"),
  handler: async (ctx, args) => {
    // TENTAR BETTER AUTH PRIMEIRO
    const identity = await ctx.auth.getUserIdentity();

    let usuarioAtual = null;

    if (identity && identity.email) {
      // Buscar por email (Better Auth)
      usuarioAtual = await ctx.db
        .query("usuarios")
        .withIndex("by_email", (q) => q.eq("email", identity.email!))
        .first();
    }

    // SE NÃO ENCONTROU, BUSCAR POR SESSÃO ATIVA (Sistema customizado)
    if (!usuarioAtual) {
      const sessaoAtiva = await ctx.db
        .query("sessoes")
        .filter((q) => q.eq(q.field("ativo"), true))
        .order("desc")
        .first();

      if (sessaoAtiva) {
        usuarioAtual = await ctx.db.get(sessaoAtiva.usuarioId);
      }
    }

    if (!usuarioAtual) throw new Error("Usuário não autenticado");

    // Buscar conversa individual existente entre os dois usuários
    const conversasExistentes = await ctx.db
      .query("conversas")
      .filter((q) => q.eq(q.field("tipo"), "individual"))
      .collect();

    for (const conversa of conversasExistentes) {
      if (
        conversa.participantes.length === 2 &&
        conversa.participantes.includes(usuarioAtual._id) &&
        conversa.participantes.includes(args.outroUsuarioId)
      ) {
        return conversa._id;
      }
    }

    // Se não existe, criar nova conversa individual
    const conversaId = await ctx.db.insert("conversas", {
      tipo: "individual",
      participantes: [usuarioAtual._id, args.outroUsuarioId],
      criadoPor: usuarioAtual._id,
      criadoEm: Date.now(),
    });

    return conversaId;
  },
});

/**
 * Envia uma mensagem em uma conversa
 */
export const enviarMensagem = mutation({
  args: {
    conversaId: v.id("conversas"),
    conteudo: v.string(),
    tipo: v.union(
      v.literal("texto"),
      v.literal("arquivo"),
      v.literal("imagem")
    ),
    arquivoId: v.optional(v.id("_storage")),
    arquivoNome: v.optional(v.string()),
    arquivoTamanho: v.optional(v.number()),
    arquivoTipo: v.optional(v.string()),
    mencoes: v.optional(v.array(v.id("usuarios"))),
    permitirNotificacaoParaSiMesmo: v.optional(v.boolean()), // ✅ NOVO: Permite criar notificação para si mesmo
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    // Verificar se usuário pertence à conversa
    const conversa = await ctx.db.get(args.conversaId);
    if (!conversa) throw new Error("Conversa não encontrada");
    if (!conversa.participantes.includes(usuarioAtual._id)) {
      throw new Error("Você não pertence a esta conversa");
    }

    // Criar mensagem
    const mensagemId = await ctx.db.insert("mensagens", {
      conversaId: args.conversaId,
      remetenteId: usuarioAtual._id,
      tipo: args.tipo,
      conteudo: args.conteudo,
      arquivoId: args.arquivoId,
      arquivoNome: args.arquivoNome,
      arquivoTamanho: args.arquivoTamanho,
      arquivoTipo: args.arquivoTipo,
      mencoes: args.mencoes,
      enviadaEm: Date.now(),
    });

    // Atualizar última mensagem da conversa
    await ctx.db.patch(args.conversaId, {
      ultimaMensagem: args.conteudo.substring(0, 100),
      ultimaMensagemTimestamp: Date.now(),
    });

    // Criar notificações para participantes (com tratamento de erro)
    try {
      for (const participanteId of conversa.participantes) {
        // ✅ MODIFICADO: Permite notificação para si mesmo se flag estiver ativa
        const ehOMesmoUsuario = participanteId === usuarioAtual._id;
        const deveCriarNotificacao = !ehOMesmoUsuario || args.permitirNotificacaoParaSiMesmo;
        
        if (deveCriarNotificacao) {
          const tipoNotificacao = args.mencoes?.includes(participanteId)
            ? "mencao"
            : "nova_mensagem";

          await ctx.db.insert("notificacoes", {
            usuarioId: participanteId,
            tipo: tipoNotificacao,
            conversaId: args.conversaId,
            mensagemId,
            remetenteId: usuarioAtual._id,
            titulo:
              tipoNotificacao === "mencao"
                ? `${usuarioAtual.nome} mencionou você`
                : `Nova mensagem de ${usuarioAtual.nome}`,
            descricao: args.conteudo.substring(0, 100),
            lida: false,
            criadaEm: Date.now(),
          });
        }
      }
    } catch (error) {
      // Log do erro mas não falhar o envio da mensagem
      console.error("Erro ao criar notificações:", error);
      // A mensagem já foi criada, então retornamos o ID normalmente
    }

    return mensagemId;
  },
});

/**
 * Agenda uma mensagem para envio futuro
 */
export const agendarMensagem = mutation({
  args: {
    conversaId: v.id("conversas"),
    conteudo: v.string(),
    agendadaPara: v.number(), // timestamp
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    // Validar data futura
    if (args.agendadaPara <= Date.now()) {
      throw new Error("Data de agendamento deve ser futura");
    }

    // Verificar se usuário pertence à conversa
    const conversa = await ctx.db.get(args.conversaId);
    if (!conversa) throw new Error("Conversa não encontrada");
    if (!conversa.participantes.includes(usuarioAtual._id)) {
      throw new Error("Você não pertence a esta conversa");
    }

    // Criar mensagem agendada
    const mensagemId = await ctx.db.insert("mensagens", {
      conversaId: args.conversaId,
      remetenteId: usuarioAtual._id,
      tipo: "texto",
      conteudo: args.conteudo,
      agendadaPara: args.agendadaPara,
      enviadaEm: args.agendadaPara, // Será usada quando a mensagem for enviada
    });

    return mensagemId;
  },
});

/**
 * Cancela uma mensagem agendada
 */
export const cancelarMensagemAgendada = mutation({
  args: {
    mensagemId: v.id("mensagens"),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    const mensagem = await ctx.db.get(args.mensagemId);
    if (!mensagem) throw new Error("Mensagem não encontrada");
    if (mensagem.remetenteId !== usuarioAtual._id) {
      throw new Error("Você só pode cancelar suas próprias mensagens");
    }

    await ctx.db.delete(args.mensagemId);
    return true;
  },
});

/**
 * Adiciona uma reação (emoji) a uma mensagem
 */
export const reagirMensagem = mutation({
  args: {
    mensagemId: v.id("mensagens"),
    emoji: v.string(),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    const mensagem = await ctx.db.get(args.mensagemId);
    if (!mensagem) throw new Error("Mensagem não encontrada");

    const reacoes = mensagem.reagiuPor || [];
    const reacaoExistente = reacoes.find(
      (r) => r.usuarioId === usuarioAtual._id && r.emoji === args.emoji
    );

    if (reacaoExistente) {
      // Remover reação
      await ctx.db.patch(args.mensagemId, {
        reagiuPor: reacoes.filter(
          (r) => !(r.usuarioId === usuarioAtual._id && r.emoji === args.emoji)
        ),
      });
    } else {
      // Adicionar reação
      await ctx.db.patch(args.mensagemId, {
        reagiuPor: [
          ...reacoes,
          { usuarioId: usuarioAtual._id, emoji: args.emoji },
        ],
      });
    }

    return true;
  },
});

/**
 * Marca mensagens de uma conversa como lidas
 */
export const marcarComoLida = mutation({
  args: {
    conversaId: v.id("conversas"),
    mensagemId: v.id("mensagens"),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    // Buscar registro de leitura existente
    const leituraExistente = await ctx.db
      .query("leituras")
      .withIndex("by_conversa_usuario", (q) =>
        q.eq("conversaId", args.conversaId).eq("usuarioId", usuarioAtual._id)
      )
      .first();

    if (leituraExistente) {
      await ctx.db.patch(leituraExistente._id, {
        ultimaMensagemLida: args.mensagemId,
        lidaEm: Date.now(),
      });
    } else {
      await ctx.db.insert("leituras", {
        conversaId: args.conversaId,
        usuarioId: usuarioAtual._id,
        ultimaMensagemLida: args.mensagemId,
        lidaEm: Date.now(),
      });
    }

    // Marcar notificações desta conversa como lidas
    const notificacoes = await ctx.db
      .query("notificacoes")
      .withIndex("by_usuario_lida", (q) =>
        q.eq("usuarioId", usuarioAtual._id).eq("lida", false)
      )
      .filter((q) => q.eq(q.field("conversaId"), args.conversaId))
      .collect();

    for (const notificacao of notificacoes) {
      await ctx.db.patch(notificacao._id, { lida: true });
    }

    return true;
  },
});

/**
 * Atualiza o status de presença do usuário
 */
export const atualizarStatusPresenca = mutation({
  args: {
    status: v.union(
      v.literal("online"),
      v.literal("offline"),
      v.literal("ausente"),
      v.literal("externo"),
      v.literal("em_reuniao")
    ),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    await ctx.db.patch(usuarioAtual._id, {
      statusPresenca: args.status,
      ultimaAtividade: Date.now(),
    });

    return true;
  },
});

/**
 * Indica que o usuário está digitando em uma conversa
 */
export const indicarDigitacao = mutation({
  args: {
    conversaId: v.id("conversas"),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    // Buscar indicador existente
    const indicadorExistente = await ctx.db
      .query("digitando")
      .withIndex("by_usuario", (q) => q.eq("usuarioId", usuarioAtual._id))
      .filter((q) => q.eq(q.field("conversaId"), args.conversaId))
      .first();

    if (indicadorExistente) {
      await ctx.db.patch(indicadorExistente._id, {
        iniciouEm: Date.now(),
      });
    } else {
      await ctx.db.insert("digitando", {
        conversaId: args.conversaId,
        usuarioId: usuarioAtual._id,
        iniciouEm: Date.now(),
      });
    }

    return true;
  },
});

/**
 * Gera URL para upload de arquivo no chat
 */
export const uploadArquivoChat = mutation({
  args: {
    conversaId: v.id("conversas"),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    // Verificar se usuário pertence à conversa
    const conversa = await ctx.db.get(args.conversaId);
    if (!conversa) throw new Error("Conversa não encontrada");

    if (!conversa.participantes.includes(usuarioAtual._id)) {
      throw new Error("Você não pertence a esta conversa");
    }

    return await ctx.storage.generateUploadUrl();
  },
});

/**
 * Marca uma notificação como lida
 */
export const marcarNotificacaoLida = mutation({
  args: {
    notificacaoId: v.id("notificacoes"),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    await ctx.db.patch(args.notificacaoId, { lida: true });
    return true;
  },
});

/**
 * Marca todas as notificações como lidas
 */
export const marcarTodasNotificacoesLidas = mutation({
  args: {},
  handler: async (ctx) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    const notificacoes = await ctx.db
      .query("notificacoes")
      .withIndex("by_usuario_lida", (q) =>
        q.eq("usuarioId", usuarioAtual._id).eq("lida", false)
      )
      .collect();

    for (const notificacao of notificacoes) {
      await ctx.db.patch(notificacao._id, { lida: true });
    }

    return true;
  },
});

/**
 * Deleta uma mensagem (soft delete)
 */
export const deletarMensagem = mutation({
  args: {
    mensagemId: v.id("mensagens"),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) throw new Error("Não autenticado");

    const mensagem = await ctx.db.get(args.mensagemId);
    if (!mensagem) throw new Error("Mensagem não encontrada");

    if (mensagem.remetenteId !== usuarioAtual._id) {
      throw new Error("Você só pode deletar suas próprias mensagens");
    }

    await ctx.db.patch(args.mensagemId, {
      deletada: true,
      conteudo: "Mensagem deletada",
    });

    return true;
  },
});

// ========== QUERIES ==========

/**
 * Lista todas as conversas do usuário logado
 */
export const listarConversas = query({
  args: {},
  handler: async (ctx) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) return [];

    // Buscar todas as conversas do usuário
    const todasConversas = await ctx.db.query("conversas").collect();
    const conversasDoUsuario = todasConversas.filter((c) =>
      c.participantes.includes(usuarioAtual._id)
    );

    // Ordenar por última mensagem
    conversasDoUsuario.sort((a, b) => {
      const timestampA = a.ultimaMensagemTimestamp || a.criadoEm;
      const timestampB = b.ultimaMensagemTimestamp || b.criadoEm;
      return timestampB - timestampA;
    });

    // Enriquecer com informações dos participantes
    const conversasEnriquecidas = await Promise.all(
      conversasDoUsuario.map(async (conversa) => {
        // Buscar participantes
        const participantes = await Promise.all(
          conversa.participantes.map((id) => ctx.db.get(id))
        );

        // Para conversas individuais, pegar o outro usuário
        let outroUsuario = null;
        if (conversa.tipo === "individual") {
          const outroUsuarioRaw = participantes.find((p) => p?._id !== usuarioAtual._id);
          if (outroUsuarioRaw) {
            // 🔄 BUSCAR DADOS ATUALIZADOS DO USUÁRIO (não usar snapshot)
            const usuarioAtualizado = await ctx.db.get(outroUsuarioRaw._id);
            
            if (usuarioAtualizado) {
              // Adicionar URL da foto de perfil
              let fotoPerfilUrl = null;
              if (usuarioAtualizado.fotoPerfil) {
                fotoPerfilUrl = await ctx.storage.getUrl(usuarioAtualizado.fotoPerfil);
              }
              outroUsuario = {
                ...usuarioAtualizado,
                fotoPerfilUrl,
              };
            }
          }
        }

        // Contar mensagens não lidas (apenas mensagens NÃO agendadas)
        const leitura = await ctx.db
          .query("leituras")
          .withIndex("by_conversa_usuario", (q) =>
            q.eq("conversaId", conversa._id).eq("usuarioId", usuarioAtual._id)
          )
          .first();

        // CORRIGIDO: Buscar apenas mensagens NÃO agendadas (agendadaPara === undefined)
        const todasMensagens = await ctx.db
          .query("mensagens")
          .withIndex("by_conversa", (q) => q.eq("conversaId", conversa._id))
          .collect();
        
        const mensagens = todasMensagens.filter((m) => !m.agendadaPara);

        let naoLidas = 0;
        if (leitura) {
          naoLidas = mensagens.filter(
            (m) =>
              m.enviadaEm > (leitura.lidaEm || 0) &&
              m.remetenteId !== usuarioAtual._id
          ).length;
        } else {
          naoLidas = mensagens.filter(
            (m) => m.remetenteId !== usuarioAtual._id
          ).length;
        }

        return {
          ...conversa,
          outroUsuario,
          participantesInfo: participantes.filter((p) => p !== null),
          naoLidas,
        };
      })
    );

    return conversasEnriquecidas;
  },
});

/**
 * Obtém as mensagens de uma conversa com paginação
 */
export const obterMensagens = query({
  args: {
    conversaId: v.id("conversas"),
    limit: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) return [];

    // Verificar se usuário pertence à conversa
    const conversa = await ctx.db.get(args.conversaId);
    if (!conversa || !conversa.participantes.includes(usuarioAtual._id)) {
      return [];
    }

    // Buscar mensagens (excluir agendadas)
    const mensagens = await ctx.db
      .query("mensagens")
      .withIndex("by_conversa", (q) => q.eq("conversaId", args.conversaId))
      .order("desc")
      .take(args.limit || 50);

    // Filtrar mensagens agendadas
    const mensagensFiltradas = mensagens.filter((m) => !m.agendadaPara);

    // Enriquecer com informações do remetente
    const mensagensEnriquecidas = await Promise.all(
      mensagensFiltradas.map(async (mensagem) => {
        const remetente = await ctx.db.get(mensagem.remetenteId);
        let arquivoUrl = null;
        if (mensagem.arquivoId) {
          arquivoUrl = await ctx.storage.getUrl(mensagem.arquivoId);
        }
        return {
          ...mensagem,
          remetente,
          arquivoUrl,
        };
      })
    );

    return mensagensEnriquecidas.reverse();
  },
});

/**
 * Obtém mensagens agendadas de uma conversa
 */
export const obterMensagensAgendadas = query({
  args: {
    conversaId: v.id("conversas"),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) return [];

    // Buscar mensagens agendadas
    const todasMensagens = await ctx.db
      .query("mensagens")
      .withIndex("by_conversa", (q) => q.eq("conversaId", args.conversaId))
      .collect();

    // Filtrar apenas as agendadas do usuário atual
    const minhasMensagensAgendadas = todasMensagens.filter(
      (m) =>
        m.remetenteId === usuarioAtual._id &&
        m.agendadaPara &&
        m.agendadaPara > Date.now()
    );

    return minhasMensagensAgendadas.sort(
      (a, b) => (a.agendadaPara || 0) - (b.agendadaPara || 0)
    );
  },
});

/**
 * Obtém as notificações do usuário
 */
export const obterNotificacoes = query({
  args: {
    apenasPendentes: v.optional(v.boolean()),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) return [];

    let query = ctx.db
      .query("notificacoes")
      .withIndex("by_usuario", (q) => q.eq("usuarioId", usuarioAtual._id));

    if (args.apenasPendentes) {
      query = ctx.db
        .query("notificacoes")
        .withIndex("by_usuario_lida", (q) =>
          q.eq("usuarioId", usuarioAtual._id).eq("lida", false)
        );
    }

    const notificacoes = await query.order("desc").take(50);

    // Enriquecer com informações do remetente
    const notificacoesEnriquecidas = await Promise.all(
      notificacoes.map(async (notificacao) => {
        let remetente = null;
        if (notificacao.remetenteId) {
          remetente = await ctx.db.get(notificacao.remetenteId);
        }
        return {
          ...notificacao,
          remetente,
        };
      })
    );

    return notificacoesEnriquecidas;
  },
});

/**
 * Conta o número de notificações não lidas
 */
export const contarNotificacoesNaoLidas = query({
  args: {},
  handler: async (ctx) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) return 0;

    const notificacoes = await ctx.db
      .query("notificacoes")
      .withIndex("by_usuario_lida", (q) =>
        q.eq("usuarioId", usuarioAtual._id).eq("lida", false)
      )
      .collect();

    return notificacoes.length;
  },
});

/**
 * Obtém usuários online
 */
export const obterUsuariosOnline = query({
  args: {},
  handler: async (ctx) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) return [];

    const usuarios = await ctx.db
      .query("usuarios")
      .withIndex("by_status_presenca", (q) => q.eq("statusPresenca", "online"))
      .collect();

    return usuarios.map((u) => ({
      _id: u._id,
      nome: u.nome,
      email: u.email,
      avatar: u.avatar,
      fotoPerfil: u.fotoPerfil,
      statusPresenca: u.statusPresenca,
      statusMensagem: u.statusMensagem,
      setor: u.setor,
    }));
  },
});

/**
 * Lista todos os usuários (para criar nova conversa)
 */
export const listarTodosUsuarios = query({
  args: {},
  handler: async (ctx) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) return [];

    const usuarios = await ctx.db
      .query("usuarios")
      .withIndex("by_ativo", (q) => q.eq("ativo", true))
      .collect();

    // Excluir o usuário atual
    return usuarios
      .filter((u) => u._id !== usuarioAtual._id)
      .map((u) => ({
        _id: u._id,
        nome: u.nome,
        email: u.email,
        matricula: u.matricula,
        avatar: u.avatar,
        fotoPerfil: u.fotoPerfil,
        statusPresenca: u.statusPresenca,
        statusMensagem: u.statusMensagem,
        setor: u.setor,
      }));
  },
});

/**
 * Busca mensagens em conversas
 */
export const buscarMensagens = query({
  args: {
    query: v.string(),
    conversaId: v.optional(v.id("conversas")),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) return [];

    // Buscar em todas as conversas do usuário
    const todasConversas = await ctx.db.query("conversas").collect();
    const conversasDoUsuario = todasConversas.filter((c) =>
      c.participantes.includes(usuarioAtual._id)
    );

    let mensagens: any[] = [];

    if (args.conversaId !== undefined) {
      // Buscar em conversa específica
      const mensagensConversa = await ctx.db
        .query("mensagens")
        .withIndex("by_conversa", (q) => q.eq("conversaId", args.conversaId!))
        .collect();
      mensagens = mensagensConversa;
    } else {
      // Buscar em todas as conversas
      for (const conversa of conversasDoUsuario) {
        const mensagensConversa = await ctx.db
          .query("mensagens")
          .withIndex("by_conversa", (q) => q.eq("conversaId", conversa._id))
          .collect();
        mensagens.push(...mensagensConversa);
      }
    }

    // Filtrar por query
    const queryLower = args.query.toLowerCase();
    const mensagensFiltradas = mensagens.filter(
      (m) =>
        !m.deletada &&
        !m.agendadaPara &&
        m.conteudo.toLowerCase().includes(queryLower)
    );

    // Enriquecer com informações
    const mensagensEnriquecidas = await Promise.all(
      mensagensFiltradas.map(async (mensagem) => {
        const remetente = await ctx.db.get(mensagem.remetenteId);
        const conversa = await ctx.db.get(mensagem.conversaId);
        return {
          ...mensagem,
          remetente,
          conversa,
        };
      })
    );

    return mensagensEnriquecidas
      .sort((a, b) => b.enviadaEm - a.enviadaEm)
      .slice(0, 50);
  },
});

/**
 * Obtém quem está digitando em uma conversa
 */
export const obterDigitando = query({
  args: {
    conversaId: v.id("conversas"),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) return [];

    // Buscar indicadores de digitação (últimos 10 segundos)
    const dezSegundosAtras = Date.now() - 10000;
    const digitando = await ctx.db
      .query("digitando")
      .withIndex("by_conversa", (q) => q.eq("conversaId", args.conversaId))
      .filter((q) => q.gte(q.field("iniciouEm"), dezSegundosAtras))
      .collect();

    // Filtrar usuário atual e buscar informações
    const digitandoFiltrado = digitando.filter(
      (d) => d.usuarioId !== usuarioAtual._id
    );

    const usuarios = await Promise.all(
      digitandoFiltrado.map(async (d) => {
        const usuario = await ctx.db.get(d.usuarioId);
        return usuario;
      })
    );

    return usuarios.filter((u) => u !== null);
  },
});

/**
 * Conta mensagens não lidas de uma conversa
 */
export const contarNaoLidas = query({
  args: {
    conversaId: v.id("conversas"),
  },
  handler: async (ctx, args) => {
    const usuarioAtual = await getUsuarioAutenticado(ctx);
    if (!usuarioAtual) return 0;

    const leitura = await ctx.db
      .query("leituras")
      .withIndex("by_conversa_usuario", (q) =>
        q.eq("conversaId", args.conversaId).eq("usuarioId", usuarioAtual._id)
      )
      .first();

    const mensagens = await ctx.db
      .query("mensagens")
      .withIndex("by_conversa", (q) => q.eq("conversaId", args.conversaId))
      .filter((q) => q.eq(q.field("agendadaPara"), undefined))
      .collect();

    if (leitura) {
      return mensagens.filter(
        (m) =>
          m.enviadaEm > (leitura.lidaEm || 0) &&
          m.remetenteId !== usuarioAtual._id
      ).length;
    }

    return mensagens.filter((m) => m.remetenteId !== usuarioAtual._id).length;
  },
});

// ========== INTERNAL MUTATIONS (para crons) ==========

/**
 * Envia mensagens agendadas (chamado pelo cron)
 */
export const enviarMensagensAgendadas = internalMutation({
  args: {},
  handler: async (ctx) => {
    const agora = Date.now();

    // Buscar mensagens que deveriam ser enviadas
    const mensagensAgendadas = await ctx.db
      .query("mensagens")
      .withIndex("by_agendamento")
      .filter((q) =>
        q.and(
          q.neq(q.field("agendadaPara"), undefined),
          q.lte(q.field("agendadaPara"), agora)
        )
      )
      .collect();

    for (const mensagem of mensagensAgendadas) {
      // Atualizar mensagem para "enviada"
      await ctx.db.patch(mensagem._id, {
        agendadaPara: undefined,
        enviadaEm: agora,
      });

      // Atualizar última mensagem da conversa
      const conversa = await ctx.db.get(mensagem.conversaId);
      if (conversa) {
        await ctx.db.patch(mensagem.conversaId, {
          ultimaMensagem: mensagem.conteudo.substring(0, 100),
          ultimaMensagemTimestamp: agora,
        });

        // Criar notificações para outros participantes
        const remetente = await ctx.db.get(mensagem.remetenteId);
        for (const participanteId of conversa.participantes) {
          if (participanteId !== mensagem.remetenteId) {
            await ctx.db.insert("notificacoes", {
              usuarioId: participanteId,
              tipo: "nova_mensagem",
              conversaId: mensagem.conversaId,
              mensagemId: mensagem._id,
              remetenteId: mensagem.remetenteId,
              titulo: `Nova mensagem de ${remetente?.nome || "Usuário"}`,
              descricao: mensagem.conteudo.substring(0, 100),
              lida: false,
              criadaEm: agora,
            });
          }
        }
      }
    }

    return mensagensAgendadas.length;
  },
});

/**
 * Limpa indicadores de digitação antigos (chamado pelo cron)
 */
export const limparIndicadoresDigitacao = internalMutation({
  args: {},
  handler: async (ctx) => {
    const dezSegundosAtras = Date.now() - 10000;

    const indicadoresAntigos = await ctx.db
      .query("digitando")
      .filter((q) => q.lt(q.field("iniciouEm"), dezSegundosAtras))
      .collect();

    for (const indicador of indicadoresAntigos) {
      await ctx.db.delete(indicador._id);
    }

    return indicadoresAntigos.length;
  },
});
