import { Controller, Get } from '@nestjs/common';
import { PrismaService } from '../common/prisma.service';
import { getMerchant } from '../common/core';

@Controller('admin')
export class DashboardController {
  constructor(private prisma: PrismaService) {}

  @Get('dashboard')
  async dashboard() {
    const m = await getMerchant(this.prisma);
    const [active, pending, orders, clicks, bal, recent] = await Promise.all([
      this.prisma.affiliate.count({ where: { merchantId: m.id, status: 'ACTIVE' } }),
      this.prisma.affiliate.count({ where: { merchantId: m.id, status: 'PENDING' } }),
      this.prisma.referralOrder.findMany({ where: { merchantId: m.id }, select: { total: true } }),
      this.prisma.click.count({ where: { affiliate: { merchantId: m.id } } }),
      this.prisma.affiliate.aggregate({ where: { merchantId: m.id }, _sum: { balance: true } }),
      this.prisma.affiliate.findMany({
        where: { merchantId: m.id },
        orderBy: { createdAt: 'desc' },
        take: 6,
        select: { id: true, name: true, email: true, status: true, createdAt: true },
      }),
    ]);
    const revenue = orders.reduce((s, o) => s + Number(o.total), 0);
    return {
      programName: m.programName,
      shop: m.shop,
      revenue,
      commissionsOwed: Number(bal._sum.balance ?? 0),
      activeAffiliates: active,
      pendingAffiliates: pending,
      clicks,
      conversions: orders.length,
      convRate: clicks ? (orders.length / clicks) * 100 : 0,
      recentAffiliates: recent.map((a) => ({
        id: a.id,
        name: a.name,
        email: a.email,
        status: a.status,
        date: a.createdAt.toISOString().slice(0, 10),
      })),
    };
  }

  /** Real time-series + breakdowns for the dashboard charts (no dummy data). */
  @Get('analytics')
  async analytics() {
    const m = await getMerchant(this.prisma);

    const since = new Date();
    since.setDate(since.getDate() - 13);
    since.setHours(0, 0, 0, 0);

    const [recent, grouped, statusCounts] = await Promise.all([
      this.prisma.referralOrder.findMany({
        where: { merchantId: m.id, createdAt: { gte: since } },
        select: { total: true, commission: true, createdAt: true },
      }),
      this.prisma.referralOrder.groupBy({
        by: ['affiliateId'],
        where: { merchantId: m.id },
        _sum: { commission: true },
        _count: { _all: true },
      }),
      this.prisma.affiliate.groupBy({
        by: ['status'],
        where: { merchantId: m.id },
        _count: { _all: true },
      }),
    ]);

    // 14-day buckets
    const buckets: Record<string, { revenue: number; commission: number; orders: number }> = {};
    const days: { date: string; label: string; revenue: number; commission: number; orders: number }[] = [];
    for (let i = 13; i >= 0; i--) {
      const d = new Date();
      d.setDate(d.getDate() - i);
      d.setHours(0, 0, 0, 0);
      const key = d.toISOString().slice(0, 10);
      buckets[key] = { revenue: 0, commission: 0, orders: 0 };
      days.push({
        date: key,
        label: d.toLocaleDateString('en-IN', { day: 'numeric', month: 'short' }),
        revenue: 0,
        commission: 0,
        orders: 0,
      });
    }
    for (const o of recent) {
      const key = o.createdAt.toISOString().slice(0, 10);
      if (buckets[key]) {
        buckets[key].revenue += Number(o.total);
        buckets[key].commission += Number(o.commission);
        buckets[key].orders += 1;
      }
    }
    for (const day of days) {
      const b = buckets[day.date];
      day.revenue = Math.round(b.revenue);
      day.commission = Math.round(b.commission);
      day.orders = b.orders;
    }

    // Top affiliates by lifetime commission
    const topIds = grouped
      .map((g) => ({ id: g.affiliateId, earnings: Number(g._sum.commission ?? 0), sales: g._count._all }))
      .sort((a, b) => b.earnings - a.earnings)
      .slice(0, 5);
    const names = await this.prisma.affiliate.findMany({
      where: { id: { in: topIds.map((t) => t.id) } },
      select: { id: true, name: true },
    });
    const nameMap = new Map(names.map((n) => [n.id, n.name]));
    const topAffiliates = topIds.map((t) => ({
      name: nameMap.get(t.id) ?? '—',
      earnings: t.earnings,
      sales: t.sales,
    }));

    const statusBreakdown = { ACTIVE: 0, PENDING: 0, REJECTED: 0 } as Record<string, number>;
    for (const s of statusCounts) statusBreakdown[s.status] = s._count._all;

    return { days, topAffiliates, statusBreakdown };
  }

  // --- Leaderboard (PRD 4.7) ---
  @Get('leaderboard')
  async leaderboard() {
    const m = await getMerchant(this.prisma);
    const grouped = await this.prisma.referralOrder.groupBy({
      by: ['affiliateId'],
      where: { merchantId: m.id, status: { in: ['APPROVED', 'PENDING'] } },
      _sum: { commission: true, total: true },
      _count: { _all: true },
    });
    const affs = await this.prisma.affiliate.findMany({ where: { merchantId: m.id }, select: { id: true, name: true, email: true } });
    const map = new Map(affs.map((a) => [a.id, a]));
    return grouped
      .map((g) => ({
        name: map.get(g.affiliateId)?.name ?? '—',
        email: map.get(g.affiliateId)?.email ?? '',
        sales: g._count._all,
        revenue: Number(g._sum.total ?? 0),
        earnings: Number(g._sum.commission ?? 0),
      }))
      .sort((a, b) => b.earnings - a.earnings);
  }
}
