import { z } from "zod";
import { protectedProcedure, publicProcedure, router } from "../_core/trpc.ts";
import { TRPCError } from "@trpc/server";
import { getDb, writeAuditLog } from "../db.ts";
import { eq, and, desc, sql } from "drizzle-orm";
// Firebase notifications temporarily disabled
// TODO: Re-enable when firebase-admin is installed
// import {
//   sendPushNotification,
//   registerDeviceForNotifications,
//   unregisterDeviceFromNotifications,
//   notifyAchievementUnlock,
//   notifyTournamentResult,
//   notifyReferralBonus,
//   notifyAdminAlert,
//   broadcastSystemNotification,
//   sendTopicNotification,
// } from "../_core/firebaseNotifications.ts";

export const notificationRouter = router({
  // Get user's notifications with pagination
  getNotifications: protectedProcedure
    .input(z.object({ limit: z.number().default(20), offset: z.number().default(0), unreadOnly: z.boolean().default(false) }))
    .query(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) return [];

      const schema = await import("../../drizzle/schema");

      const conditions = [eq(schema.notifications.userId, ctx.user.id)];
      if (input.unreadOnly) {
        conditions.push(eq(schema.notifications.isRead, false));
      }

      const result = await db
        .select()
        .from(schema.notifications)
        .where(and(...conditions))
        .orderBy(desc(schema.notifications.createdAt))
        .limit(input.limit)
        .offset(input.offset);

      return result;
    }),

  // Get unread notification count
  getUnreadCount: protectedProcedure.query(async ({ ctx }) => {
    const db = await getDb();
    if (!db) return 0;

    const schema = await import("../../drizzle/schema");
    const { sql } = await import("drizzle-orm");
    const result = await db
      .select({ count: sql`COUNT(*)`.mapWith(Number) })
      .from(schema.notifications)
      .where(and(
        eq(schema.notifications.userId, ctx.user.id),
        eq(schema.notifications.isRead, false)
      ));

    return result[0]?.count ?? 0;
  }),

  // Mark notification as read
  markAsRead: protectedProcedure
    .input(z.object({ notificationId: z.number() }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      const schema = await import("../../drizzle/schema");
      const notif = await db
        .select()
        .from(schema.notifications)
        .where(eq(schema.notifications.id, input.notificationId))
        .limit(1);

      if (!notif[0] || notif[0].userId !== ctx.user.id) {
        throw new TRPCError({ code: "FORBIDDEN", message: "Not your notification" });
      }

      await db
        .update(schema.notifications)
        .set({ isRead: true, readAt: new Date() })
        .where(eq(schema.notifications.id, input.notificationId));

      return { success: true };
    }),

  // Mark all notifications as read
  markAllAsRead: protectedProcedure.mutation(async ({ ctx }) => {
    const db = await getDb();
    if (!db) throw new Error("Database unavailable");

    const schema = await import("../../drizzle/schema");
    await db
      .update(schema.notifications)
      .set({ isRead: true, readAt: new Date() })
      .where(and(
        eq(schema.notifications.userId, ctx.user.id),
        eq(schema.notifications.isRead, false)
      ));

    return { success: true };
  }),

  // Delete notification
  deleteNotification: protectedProcedure
    .input(z.object({ notificationId: z.number() }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      const schema = await import("../../drizzle/schema");
      const notif = await db
        .select()
        .from(schema.notifications)
        .where(eq(schema.notifications.id, input.notificationId))
        .limit(1);

      if (!notif[0] || notif[0].userId !== ctx.user.id) {
        throw new TRPCError({ code: "FORBIDDEN", message: "Not your notification" });
      }

      await db
        .delete(schema.notifications)
        .where(eq(schema.notifications.id, input.notificationId));

      return { success: true };
    }),

  // Clear all notifications
  clearAll: protectedProcedure.mutation(async ({ ctx }) => {
    const db = await getDb();
    if (!db) throw new Error("Database unavailable");

    const schema = await import("../../drizzle/schema");
    await db
      .delete(schema.notifications)
      .where(eq(schema.notifications.userId, ctx.user.id));

    return { success: true };
  }),

  // Firebase Push Notifications

  // Register device for push notifications
  registerPushDevice: protectedProcedure
    .input(
      z.object({
        deviceToken: z.string(),
        deviceType: z.enum(["ios", "android", "web"]),
      })
    )
    .mutation(async ({ input, ctx }) => {
      try {
        await registerDeviceForNotifications(ctx.user.id.toString(), input.deviceToken, input.deviceType);
        return { success: true };
      } catch (error) {
        console.error("[Notifications] Failed to register device:", error);
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: "Failed to register device for notifications",
        });
      }
    }),

  // Unregister device from push notifications
  unregisterPushDevice: protectedProcedure
    .input(
      z.object({
        deviceToken: z.string(),
      })
    )
    .mutation(async ({ input }) => {
      try {
        await unregisterDeviceFromNotifications(input.deviceToken);
        return { success: true };
      } catch (error) {
        console.error("[Notifications] Failed to unregister device:", error);
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: "Failed to unregister device",
        });
      }
    }),

  // Send test push notification
  sendTestPush: protectedProcedure
    .input(
      z.object({
        deviceToken: z.string(),
        title: z.string(),
        body: z.string(),
      })
    )
    .mutation(async ({ input }) => {
      try {
        await sendPushNotification(input.deviceToken, {
          title: input.title,
          body: input.body,
          priority: "high",
        });
        return { success: true };
      } catch (error) {
        console.error("[Notifications] Failed to send test push:", error);
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: "Failed to send notification",
        });
      }
    }),

  // Broadcast system notification to all users
  broadcastSystemPush: protectedProcedure
    .input(
      z.object({
        title: z.string(),
        body: z.string(),
        data: z.record(z.string()).optional(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      // Check if user is admin
      if (ctx.user.role !== "admin") {
        throw new TRPCError({
          code: "FORBIDDEN",
          message: "Only admins can broadcast notifications",
        });
      }

      try {
        await broadcastSystemNotification(input.title, input.body, input.data);
        return { success: true };
      } catch (error) {
        console.error("[Notifications] Failed to broadcast:", error);
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: "Failed to broadcast notification",
        });
      }
    }),

  // Get notification preferences
  getPreferences: protectedProcedure.query(async ({ ctx }) => {
    const db = await getDb();
    if (!db) return null;

    const schema = await import("../../drizzle/schema");
    const prefs = await db
      .select()
      .from(schema.notificationPreferences)
      .where(eq(schema.notificationPreferences.userId, ctx.user.id))
      .limit(1);

    if (prefs.length === 0) {
      // Create default preferences
      await db.insert(schema.notificationPreferences).values({
        userId: ctx.user.id,
      } as any);
      return {
        userId: ctx.user.id,
        emailNotifications: true,
        pushNotifications: true,
        inAppNotifications: true,
        paymentNotifications: true,
        gameNotifications: true,
        promotionalNotifications: false,
        systemAlerts: true,
        emailFrequency: "instant",
      };
    }

    return prefs[0];
  }),

  // Update notification preferences
  updatePreferences: protectedProcedure
    .input(z.object({
      emailNotifications: z.boolean().optional(),
      pushNotifications: z.boolean().optional(),
      inAppNotifications: z.boolean().optional(),
      paymentNotifications: z.boolean().optional(),
      gameNotifications: z.boolean().optional(),
      promotionalNotifications: z.boolean().optional(),
      systemAlerts: z.boolean().optional(),
      emailFrequency: z.enum(["instant", "daily", "weekly", "never"]).optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      const schema = await import("../../drizzle/schema");

      // Ensure preferences exist
      const existing = await db
        .select()
        .from(schema.notificationPreferences)
        .where(eq(schema.notificationPreferences.userId, ctx.user.id))
        .limit(1);

      if (existing.length === 0) {
        await db.insert(schema.notificationPreferences).values({
          userId: ctx.user.id,
        } as any);
      }

      // Update preferences
      const updates: any = {};
      if (input.emailNotifications !== undefined) updates.emailNotifications = input.emailNotifications;
      if (input.pushNotifications !== undefined) updates.pushNotifications = input.pushNotifications;
      if (input.inAppNotifications !== undefined) updates.inAppNotifications = input.inAppNotifications;
      if (input.paymentNotifications !== undefined) updates.paymentNotifications = input.paymentNotifications;
      if (input.gameNotifications !== undefined) updates.gameNotifications = input.gameNotifications;
      if (input.promotionalNotifications !== undefined) updates.promotionalNotifications = input.promotionalNotifications;
      if (input.systemAlerts !== undefined) updates.systemAlerts = input.systemAlerts;
      if (input.emailFrequency !== undefined) updates.emailFrequency = input.emailFrequency;

      await db
        .update(schema.notificationPreferences)
        .set(updates)
        .where(eq(schema.notificationPreferences.userId, ctx.user.id));

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

// Helper function to create notifications (called from other routers)
export async function createNotification(
  userId: number,
  type: string,
  title: string,
  message: string,
  channels: string[] = ["in_app"],
  data?: any
) {
  const db = await getDb();
  if (!db) {
    console.warn("[Notification] Database unavailable");
    return null;
  }

  try {
    const schema = await import("../../drizzle/schema");

    // Check user preferences
    const prefs = await db
      .select()
      .from(schema.notificationPreferences)
      .where(eq(schema.notificationPreferences.userId, userId))
      .limit(1);

    const userPrefs = prefs[0];

    // Filter channels based on preferences
    let activeChannels = channels;
    if (userPrefs) {
      activeChannels = channels.filter(ch => {
        if (ch === "email" && !userPrefs.emailNotifications) return false;
        if (ch === "push" && !userPrefs.pushNotifications) return false;
        if (ch === "in_app" && !userPrefs.inAppNotifications) return false;
        return true;
      });
    }

    if (activeChannels.length === 0) return null;

    // Create notification
    const result = await db.insert(schema.notifications).values({
      userId,
      type: type as any,
      title,
      message,
      channels: JSON.stringify(activeChannels),
      data: data ? JSON.stringify(data) : null,
    } as any);

    console.log(`[Notification] Created for user ${userId}: ${type}`);
    return result;
  } catch (err: any) {
    console.error("[Notification] Failed to create:", err.message);
    return null;
  }
}
