import { router, adminProcedure } from "../_core/trpc.ts";
import { z } from "zod";
import { getDb } from "../db.ts";
import { promoBanners, bannerAnalytics } from "../../drizzle/schema.ts";
import { eq, desc, gte, lte } from "drizzle-orm";

export const bannerAnalyticsRouter = router({
  /**
   * Get banner analytics with daily trends
   */
  getBannerAnalytics: adminProcedure
    .input(
      z.object({
        dateRange: z.enum(["7d", "30d", "90d"]).default("30d"),
        bannerId: z.string().optional(),
      })
    )
    .query(async ({ input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      // Calculate date range
      const endDate = new Date();
      const startDate = new Date();
      const days = input.dateRange === "7d" ? 7 : input.dateRange === "30d" ? 30 : 90;
      startDate.setDate(startDate.getDate() - days);

      // Get banners
      let bannersQuery = db.select().from(promoBanners);
      if (input.bannerId) {
        bannersQuery = bannersQuery.where(eq(promoBanners.id, input.bannerId));
      }
      const banners = await bannersQuery;

      // Get analytics data
      let analyticsQuery = db
        .select()
        .from(bannerAnalytics)
        .where(gte(bannerAnalytics.date, startDate));

      if (input.bannerId) {
        analyticsQuery = analyticsQuery.where(eq(bannerAnalytics.bannerId, input.bannerId));
      }

      const analytics = await analyticsQuery;

      // Calculate summary statistics
      const summary = {
        totalImpressions: 0,
        totalClicks: 0,
        ctr: 0,
        conversions: 0,
        conversionRate: 0,
        totalRevenue: 0,
      };

      const dailyTrend: Array<{
        date: string;
        impressions: number;
        clicks: number;
        revenue: number;
      }> = [];

      const bannerStats: Array<{
        id: string;
        name: string;
        impressions: number;
        clicks: number;
        ctr: number;
        conversions: number;
        conversionRate: number;
        revenue: number;
        isActive: boolean;
      }> = [];

      // Group analytics by date
      const analyticsMap = new Map<string, typeof analytics>();
      for (const record of analytics) {
        const dateStr = record.date.toISOString().split("T")[0];
        if (!analyticsMap.has(dateStr)) {
          analyticsMap.set(dateStr, []);
        }
        analyticsMap.get(dateStr)!.push(record);
      }

      // Build daily trend
      for (let i = 0; i < days; i++) {
        const date = new Date(startDate);
        date.setDate(date.getDate() + i);
        const dateStr = date.toISOString().split("T")[0];

        const dayAnalytics = analyticsMap.get(dateStr) || [];
        const impressions = dayAnalytics.reduce((sum, a) => sum + (a.impressions || 0), 0);
        const clicks = dayAnalytics.reduce((sum, a) => sum + (a.clicks || 0), 0);
        const revenue = dayAnalytics.reduce((sum, a) => sum + (a.revenue || 0), 0);

        dailyTrend.push({
          date: dateStr,
          impressions,
          clicks,
          revenue,
        });

        summary.totalImpressions += impressions;
        summary.totalClicks += clicks;
        summary.totalRevenue += revenue;
      }

      // Calculate CTR
      summary.ctr =
        summary.totalImpressions > 0
          ? (summary.totalClicks / summary.totalImpressions) * 100
          : 0;

      // Build banner stats
      for (const banner of banners) {
        const bannerAnalytics = analytics.filter((a) => a.bannerId === banner.id);
        const impressions = bannerAnalytics.reduce((sum, a) => sum + (a.impressions || 0), 0);
        const clicks = bannerAnalytics.reduce((sum, a) => sum + (a.clicks || 0), 0);
        const conversions = bannerAnalytics.reduce((sum, a) => sum + (a.conversions || 0), 0);
        const revenue = bannerAnalytics.reduce((sum, a) => sum + (a.revenue || 0), 0);

        const ctr = impressions > 0 ? (clicks / impressions) * 100 : 0;
        const conversionRate = clicks > 0 ? (conversions / clicks) * 100 : 0;

        bannerStats.push({
          id: banner.id,
          name: banner.name,
          impressions,
          clicks,
          ctr,
          conversions,
          conversionRate,
          revenue,
          isActive: banner.isActive,
        });

        summary.conversions += conversions;
      }

      // Calculate conversion rate
      summary.conversionRate =
        summary.totalClicks > 0
          ? (summary.conversions / summary.totalClicks) * 100
          : 0;

      return {
        summary,
        dailyTrend,
        banners: bannerStats.sort((a, b) => b.revenue - a.revenue),
      };
    }),

  /**
   * Record banner interaction (impression, click, conversion)
   */
  recordBannerInteraction: adminProcedure
    .input(
      z.object({
        bannerId: z.string(),
        type: z.enum(["impression", "click", "conversion"]),
        revenue: z.number().optional(),
      })
    )
    .mutation(async ({ input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      const today = new Date();
      today.setHours(0, 0, 0, 0);

      // Get or create today's analytics record
      let record = await db.query.bannerAnalytics.findFirst({
        where: (ba) => eq(ba.bannerId, input.bannerId) && eq(ba.date, today),
      });

      if (!record) {
        await db.insert(bannerAnalytics).values({
          bannerId: input.bannerId,
          date: today,
          impressions: input.type === "impression" ? 1 : 0,
          clicks: input.type === "click" ? 1 : 0,
          conversions: input.type === "conversion" ? 1 : 0,
          revenue: input.revenue || 0,
        });
      } else {
        const updates: any = {};
        if (input.type === "impression") updates.impressions = (record.impressions || 0) + 1;
        if (input.type === "click") updates.clicks = (record.clicks || 0) + 1;
        if (input.type === "conversion") updates.conversions = (record.conversions || 0) + 1;
        if (input.revenue) updates.revenue = (record.revenue || 0) + input.revenue;

        await db
          .update(bannerAnalytics)
          .set(updates)
          .where(eq(bannerAnalytics.id, record.id));
      }

      return { success: true };
    }),

  /**
   * Get top performing banners
   */
  getTopBanners: adminProcedure
    .input(
      z.object({
        limit: z.number().min(1).max(10).default(5),
        metric: z.enum(["revenue", "ctr", "conversions"]).default("revenue"),
      })
    )
    .query(async ({ input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      // Get last 30 days analytics
      const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
      const analytics = await db
        .select()
        .from(bannerAnalytics)
        .where(gte(bannerAnalytics.date, thirtyDaysAgo));

      // Group by banner
      const bannerMap = new Map<
        string,
        { impressions: number; clicks: number; conversions: number; revenue: number }
      >();

      for (const record of analytics) {
        if (!bannerMap.has(record.bannerId)) {
          bannerMap.set(record.bannerId, {
            impressions: 0,
            clicks: 0,
            conversions: 0,
            revenue: 0,
          });
        }
        const stats = bannerMap.get(record.bannerId)!;
        stats.impressions += record.impressions || 0;
        stats.clicks += record.clicks || 0;
        stats.conversions += record.conversions || 0;
        stats.revenue += record.revenue || 0;
      }

      // Get banner details
      const banners = await db.select().from(promoBanners);

      // Calculate metrics and sort
      const results = banners
        .map((banner) => {
          const stats = bannerMap.get(banner.id) || {
            impressions: 0,
            clicks: 0,
            conversions: 0,
            revenue: 0,
          };
          const ctr =
            stats.impressions > 0 ? (stats.clicks / stats.impressions) * 100 : 0;

          return {
            id: banner.id,
            name: banner.name,
            revenue: stats.revenue,
            ctr,
            conversions: stats.conversions,
            impressions: stats.impressions,
            clicks: stats.clicks,
          };
        })
        .sort((a, b) => {
          if (input.metric === "revenue") return b.revenue - a.revenue;
          if (input.metric === "ctr") return b.ctr - a.ctr;
          return b.conversions - a.conversions;
        })
        .slice(0, input.limit);

      return results;
    }),
});
