import { v } from "convex/values";
import { mutation, query, internalMutation, internalQuery } from "./_generated/server";
import { Id } from "./_generated/dataModel";
import { internal, api } from "./_generated/api";

/**
 * Registrar subscription de push notification
 */
export const registrarPushSubscription = mutation({
  args: {
    endpoint: v.string(),
    keys: v.object({
      p256dh: v.string(),
      auth: v.string(),
    }),
    userAgent: v.optional(v.string()),
  },
  returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
  handler: async (ctx, args) => {
    // Obter usuário autenticado
    const identity = await ctx.auth.getUserIdentity();
    if (!identity?.email) {
      return { sucesso: false, erro: "Usuário não autenticado" };
    }

    const usuario = await ctx.db
      .query("usuarios")
      .withIndex("by_email", (q) => q.eq("email", identity.email!))
      .first();

    if (!usuario) {
      return { sucesso: false, erro: "Usuário não encontrado" };
    }

    // Verificar se já existe subscription com este endpoint
    const existente = await ctx.db
      .query("pushSubscriptions")
      .withIndex("by_endpoint", (q) => q.eq("endpoint", args.endpoint))
      .first();

    if (existente) {
      // Atualizar subscription existente
      await ctx.db.patch(existente._id, {
        usuarioId: usuario._id,
        keys: args.keys,
        userAgent: args.userAgent,
        ultimaAtividade: Date.now(),
        ativo: true,
      });
    } else {
      // Criar nova subscription
      await ctx.db.insert("pushSubscriptions", {
        usuarioId: usuario._id,
        endpoint: args.endpoint,
        keys: args.keys,
        userAgent: args.userAgent,
        criadoEm: Date.now(),
        ultimaAtividade: Date.now(),
        ativo: true,
      });
    }

    return { sucesso: true };
  },
});

/**
 * Remover subscription de push notification
 */
export const removerPushSubscription = mutation({
  args: {
    endpoint: v.string(),
  },
  returns: v.object({ sucesso: v.boolean() }),
  handler: async (ctx, args) => {
    const subscription = await ctx.db
      .query("pushSubscriptions")
      .withIndex("by_endpoint", (q) => q.eq("endpoint", args.endpoint))
      .first();

    if (subscription) {
      await ctx.db.patch(subscription._id, { ativo: false });
    }

    return { sucesso: true };
  },
});

/**
 * Obter subscriptions ativas de um usuário
 */
export const obterPushSubscriptions = internalQuery({
  args: {
    usuarioId: v.id("usuarios"),
  },
  returns: v.array(
    v.object({
      _id: v.id("pushSubscriptions"),
      endpoint: v.string(),
      keys: v.object({
        p256dh: v.string(),
        auth: v.string(),
      }),
    })
  ),
  handler: async (ctx, args) => {
    const subscriptions = await ctx.db
      .query("pushSubscriptions")
      .withIndex("by_usuario", (q) => q.eq("usuarioId", args.usuarioId).eq("ativo", true))
      .collect();

    return subscriptions.map((sub) => ({
      _id: sub._id,
      endpoint: sub.endpoint,
      keys: sub.keys,
    }));
  },
});

/**
 * Enviar push notification para um usuário
 * Esta função será chamada quando uma nova mensagem chegar
 */
export const enviarPushNotification = internalMutation({
  args: {
    usuarioId: v.id("usuarios"),
    titulo: v.string(),
    corpo: v.string(),
    data: v.optional(
      v.object({
        conversaId: v.optional(v.id("conversas")),
        mensagemId: v.optional(v.id("mensagens")),
        tipo: v.optional(v.string()),
      })
    ),
  },
  returns: v.object({ enviados: v.number(), falhas: v.number() }),
  handler: async (ctx, args) => {
    // Buscar subscriptions ativas do usuário
    const subscriptions = await ctx.runQuery(internal.pushNotifications.obterPushSubscriptions, {
      usuarioId: args.usuarioId,
    });

    if (subscriptions.length === 0) {
      return { enviados: 0, falhas: 0 };
    }

    // Verificar preferências do usuário
    const usuario = await ctx.db.get(args.usuarioId);
    if (!usuario || usuario.notificacoesAtivadas === false) {
      return { enviados: 0, falhas: 0 };
    }

    // Se há conversaId, verificar preferências específicas da conversa
    const conversaId = args.data?.conversaId;
    if (conversaId) {
      const preferencias = await ctx.db
        .query("preferenciasNotificacaoConversa")
        .withIndex("by_usuario_conversa", (q) =>
          q.eq("usuarioId", args.usuarioId).eq("conversaId", conversaId)
        )
        .first();

      if (preferencias) {
        // Se silenciado ou push desativado, não enviar
        if (preferencias.silenciado || !preferencias.pushAtivado) {
          return { enviados: 0, falhas: 0 };
        }

        // Se apenas menções e não é menção, não enviar
        if (preferencias.apenasMencoes && args.data?.tipo !== "mencao") {
          return { enviados: 0, falhas: 0 };
        }
      }
    }

    // Agendar envio de push via action (que roda em Node.js)
    let enviados = 0;
    let falhas = 0;

    // Converter IDs para strings ao passar para a action
    // A action espera strings, mas recebemos Ids do Convex
    const dataParaAction = args.data
      ? {
          conversaId: args.data.conversaId ? String(args.data.conversaId) : undefined,
          mensagemId: args.data.mensagemId ? String(args.data.mensagemId) : undefined,
          tipo: args.data.tipo,
        }
      : undefined;

    for (const subscription of subscriptions) {
      try {
        await ctx.scheduler.runAfter(0, api.actions.pushNotifications.enviarPush, {
          subscriptionId: subscription._id,
          titulo: args.titulo,
          corpo: args.corpo,
          data: dataParaAction,
        });
        enviados++;
      } catch (error: unknown) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        console.error(`Erro ao agendar push para subscription ${subscription._id}:`, errorMessage);
        falhas++;
      }
    }

    return { enviados, falhas };
  },
});

/**
 * Obter subscription por ID (para actions)
 */
export const getSubscriptionById = internalQuery({
  args: {
    subscriptionId: v.id("pushSubscriptions"),
  },
  returns: v.union(
    v.object({
      _id: v.id("pushSubscriptions"),
      endpoint: v.string(),
      keys: v.object({
        p256dh: v.string(),
        auth: v.string(),
      }),
      ativo: v.boolean(),
    }),
    v.null()
  ),
  handler: async (ctx, args) => {
    const subscription = await ctx.db.get(args.subscriptionId);
    if (!subscription) {
      return null;
    }

    return {
      _id: subscription._id,
      endpoint: subscription.endpoint,
      keys: subscription.keys,
      ativo: subscription.ativo,
    };
  },
});

/**
 * Marcar subscription como inativa
 */
export const marcarSubscriptionInativa = internalMutation({
  args: {
    subscriptionId: v.id("pushSubscriptions"),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    await ctx.db.patch(args.subscriptionId, { ativo: false });
    return null;
  },
});

/**
 * Verificar se usuário está online (última atividade recente)
 */
export const verificarUsuarioOnline = internalQuery({
  args: {
    usuarioId: v.id("usuarios"),
  },
  returns: v.boolean(),
  handler: async (ctx, args) => {
    const usuario = await ctx.db.get(args.usuarioId);
    if (!usuario || !usuario.ultimaAtividade) {
      return false;
    }

    // Considerar online se última atividade foi há menos de 5 minutos
    const cincoMinutosAtras = Date.now() - 5 * 60 * 1000;
    return usuario.ultimaAtividade >= cincoMinutosAtras;
  },
});

