import { router, protectedProcedure, adminProcedure } from "../_core/trpc.ts";
import { z } from "zod";
import { getDb } from "../db.ts";
import { emailCampaigns, users } from "../../drizzle/schema.ts";
import { eq, desc, and, gte, lte } from "drizzle-orm";
import { sendEmailCampaign, initializeBrevo, validateEmailList } from "../_core/brevo.ts";

export const emailCampaignsRouter = router({
  /**
   * List email campaigns with pagination
   */
  listEmailCampaigns: adminProcedure
    .input(
      z.object({
        page: z.number().min(1).default(1),
        limit: z.number().min(1).max(100).default(10),
        status: z.enum(["draft", "scheduled", "sent"]).optional(),
      })
    )
    .query(async ({ input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      const offset = (input.page - 1) * input.limit;
      const whereConditions = input.status
        ? and(eq(emailCampaigns.status, input.status))
        : undefined;

      const [campaigns, countResult] = await Promise.all([
        db
          .select()
          .from(emailCampaigns)
          .where(whereConditions)
          .orderBy(desc(emailCampaigns.createdAt))
          .limit(input.limit)
          .offset(offset),
        db
          .select({ count: emailCampaigns.id })
          .from(emailCampaigns)
          .where(whereConditions),
      ]);

      const total = countResult[0]?.count || 0;
      const draft = await db
        .select({ count: emailCampaigns.id })
        .from(emailCampaigns)
        .where(eq(emailCampaigns.status, "draft"));
      const scheduled = await db
        .select({ count: emailCampaigns.id })
        .from(emailCampaigns)
        .where(eq(emailCampaigns.status, "scheduled"));
      const sent = await db
        .select({ count: emailCampaigns.id })
        .from(emailCampaigns)
        .where(eq(emailCampaigns.status, "sent"));

      return {
        campaigns,
        total,
        pages: Math.ceil(total / input.limit),
        draft: draft.length,
        scheduled: scheduled.length,
        sent: sent.length,
      };
    }),

  /**
   * Save email campaign (create or update)
   */
  saveEmailCampaign: adminProcedure
    .input(
      z.object({
        id: z.number().optional(),
        name: z.string().min(1),
        subject: z.string().min(1),
        template: z.string().min(1),
        recipientSegment: z.enum(["all", "vip", "new", "inactive", "high-value"]),
        scheduledTime: z.string().optional(),
        status: z.enum(["draft", "scheduled", "sent"]),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      if (input.id) {
        // Update existing campaign
        await db
          .update(emailCampaigns)
          .set({
            name: input.name,
            subject: input.subject,
            template: input.template,
            recipientSegment: input.recipientSegment,
            scheduledTime: input.scheduledTime ? new Date(input.scheduledTime) : null,
            status: input.status,
            updatedAt: new Date(),
          })
          .where(eq(emailCampaigns.id, input.id));

        return { success: true, id: input.id };
      } else {
        // Create new campaign
        const result = await db.insert(emailCampaigns).values({
          name: input.name,
          subject: input.subject,
          template: input.template,
          recipientSegment: input.recipientSegment,
          scheduledTime: input.scheduledTime ? new Date(input.scheduledTime) : null,
          status: input.status,
          createdBy: ctx.user.id,
          createdAt: new Date(),
          updatedAt: new Date(),
        });

        return { success: true, id: result.insertId };
      }
    }),

  /**
   * Delete email campaign
   */
  deleteEmailCampaign: adminProcedure
    .input(z.object({ id: z.number() }))
    .mutation(async ({ input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      await db.delete(emailCampaigns).where(eq(emailCampaigns.id, input.id));

      return { success: true };
    }),

  /**
   * Send email campaign to recipients
   */
  sendEmailCampaign: adminProcedure
    .input(z.object({ id: z.number() }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      // Get campaign
      const campaign = await db.query.emailCampaigns.findFirst({
        where: eq(emailCampaigns.id, input.id),
      });

      if (!campaign) throw new Error("Campaign not found");

      // Get recipients based on segment
      let recipientQuery = db.select({ email: users.email, id: users.id }).from(users);

      if (campaign.recipientSegment === "vip") {
        // Filter VIP users (role = 'admin' or special flag)
        recipientQuery = recipientQuery.where(eq(users.role, "admin"));
      } else if (campaign.recipientSegment === "new") {
        // Filter new users (created in last 30 days)
        const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
        recipientQuery = recipientQuery.where(gte(users.createdAt, thirtyDaysAgo));
      }
      // For 'all', 'inactive', 'high-value' - implement additional logic as needed

      const recipients = await recipientQuery;

      // Initialize Brevo
      initializeBrevo({
        host: process.env.BREVO_SMTP_HOST || 'smtp-relay.brevo.com',
        port: parseInt(process.env.BREVO_SMTP_PORT || '587'),
        user: process.env.BREVO_SMTP_USER || '',
        pass: process.env.BREVO_SMTP_PASS || '',
      });

      // Validate recipient emails
      const recipientEmails = recipients.map(r => r.email);
      const { valid: validEmails } = validateEmailList(recipientEmails);

      // Send campaign via Brevo
      const sendResult = await sendEmailCampaign({
        campaignId: campaign.id.toString(),
        subject: campaign.subject,
        htmlContent: campaign.template,
        recipients: validEmails,
        fromEmail: 'noreply@playcoinkrazy.com',
        fromName: 'CoinKrazy',
        trackingEnabled: true,
      });

      if (!sendResult.success) {
        throw new Error(`Failed to send campaign: ${sendResult.error}`);
      }

      console.log(`[EmailCampaigns] Campaign ${campaign.id} sent via Brevo to ${validEmails.length} recipients`);

      // Update campaign status
      await db
        .update(emailCampaigns)
        .set({
          status: "sent",
          sentAt: new Date(),
          recipientCount: validEmails.length,
          updatedAt: new Date(),
        })
        .where(eq(emailCampaigns.id, input.id));

      return { success: true, recipientCount: validEmails.length, messageId: sendResult.messageId };
    }),

  /**
   * Get campaign statistics
   */
  getCampaignStats: adminProcedure
    .input(z.object({ id: z.number() }))
    .query(async ({ input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      const campaign = await db.query.emailCampaigns.findFirst({
        where: eq(emailCampaigns.id, input.id),
      });

      if (!campaign) throw new Error("Campaign not found");

      return {
        id: campaign.id,
        name: campaign.name,
        status: campaign.status,
        recipientCount: campaign.recipientCount || 0,
        openCount: campaign.openCount || 0,
        clickCount: campaign.clickCount || 0,
        openRate: campaign.recipientCount
          ? ((campaign.openCount || 0) / campaign.recipientCount) * 100
          : 0,
        clickRate: campaign.recipientCount
          ? ((campaign.clickCount || 0) / campaign.recipientCount) * 100
          : 0,
        sentAt: campaign.sentAt,
      };
    }),
});
