import { BadRequestException, ForbiddenException, Injectable } from '@nestjs/common';
import {
  CouponStatus,
  CustomerCouponStatus,
  SaleStatus,
  ShopStatus,
  UserRole,
} from '@prisma/client';
import { PrismaService } from '../../database/prisma.service';

@Injectable()
export class DashboardService {
  constructor(private readonly prisma: PrismaService) {}

  private async assertCanAccessShop(
    user: { id: string; role: UserRole; shopId?: string | null },
    shopId: string,
  ) {
    if (user.role === UserRole.SUPERADMIN) return;
    if (user.role === UserRole.ADMIN) {
      const shop = await this.prisma.shop.findUnique({
        where: { id: shopId },
        select: { adminId: true },
      });
      if (!shop) throw new BadRequestException('Shop not found');
      if (shop.adminId !== user.id) throw new ForbiddenException('Forbidden');
      return;
    }
    if (user.role === UserRole.SUBADMIN) {
      const linkCount = await this.prisma.subadminShop.count({
        where: { userId: user.id, shopId },
      });
      if (linkCount <= 0) throw new ForbiddenException('Forbidden');
      return;
    }
    if (!user.shopId || user.shopId !== shopId) throw new ForbiddenException('Forbidden');
  }

  private parseDateOnly(s?: string) {
    const raw = String(s ?? '').trim();
    if (!raw) return null;
    const d = new Date(raw);
    if (Number.isNaN(d.getTime())) throw new BadRequestException('Invalid date');
    return d;
  }

  async shopAnalytics(
    requester: { id: string; role: UserRole; shopId?: string | null },
    args: { from?: string; to?: string; shopId?: string },
  ) {
    const requestedShopId = (args.shopId ?? '').trim();
    const shopId =
      requester.role === UserRole.SUPERADMIN
        ? requestedShopId || null
        : requestedShopId || (requester.shopId ?? null);
    if (!shopId) throw new ForbiddenException('No shop selected');
    await this.assertCanAccessShop(requester, shopId);

    const fromDate = this.parseDateOnly(args.from);
    const toDate = this.parseDateOnly(args.to);
    if (!fromDate || !toDate)
      throw new BadRequestException('from and to are required');

    const from = new Date(fromDate);
    from.setHours(0, 0, 0, 0);
    const to = new Date(toDate);
    to.setHours(23, 59, 59, 999);
    if (from.getTime() > to.getTime())
      throw new BadRequestException('Invalid date range');

    const rangeDays = Math.max(
      1,
      Math.ceil((to.getTime() - from.getTime()) / (24 * 60 * 60 * 1000)),
    );
    const prevFrom = new Date(from);
    prevFrom.setDate(prevFrom.getDate() - rangeDays);
    const prevTo = new Date(to);
    prevTo.setDate(prevTo.getDate() - rangeDays);

    const [customersTotal, newCustomers, newCustomersPrev, salesAgg, salesAggPrev, couponsRedeemed, couponsRedeemedPrev] =
      await this.prisma.$transaction([
        this.prisma.customerShop.count({ where: { shopId } }),
        this.prisma.customerShop.count({
          where: { shopId, firstSeenAt: { gte: from, lte: to } },
        }),
        this.prisma.customerShop.count({
          where: { shopId, firstSeenAt: { gte: prevFrom, lte: prevTo } },
        }),
        this.prisma.sale.aggregate({
          where: {
            shopId,
            status: SaleStatus.COMPLETED,
            createdAt: { gte: from, lte: to },
          },
          _count: { _all: true },
          _sum: {
            amount: true,
            loyaltyPointsEarned: true,
            cashiCoinsEarned: true,
          },
        }),
        this.prisma.sale.aggregate({
          where: {
            shopId,
            status: SaleStatus.COMPLETED,
            createdAt: { gte: prevFrom, lte: prevTo },
          },
          _count: { _all: true },
          _sum: {
            amount: true,
            loyaltyPointsEarned: true,
            cashiCoinsEarned: true,
          },
        }),
        this.prisma.customerCoupon.count({
          where: {
            status: CustomerCouponStatus.REDEEMED,
            redeemedAt: { gte: from, lte: to },
            coupon: { shopId },
          },
        }),
        this.prisma.customerCoupon.count({
          where: {
            status: CustomerCouponStatus.REDEEMED,
            redeemedAt: { gte: prevFrom, lte: prevTo },
            coupon: { shopId },
          },
        }),
      ]);

    return {
      shopId,
      range: { from, to },
      prevRange: { from: prevFrom, to: prevTo },
      kpis: {
        revenue: {
          current: salesAgg._sum?.amount ?? 0,
          prev: salesAggPrev._sum?.amount ?? 0,
        },
        customers: {
          total: customersTotal,
          new: newCustomers,
          newPrev: newCustomersPrev,
        },
        cashiPointsCredited: {
          // loyalty points (₹1 = 1 point)
          current: salesAgg._sum?.loyaltyPointsEarned ?? 0,
          prev: salesAggPrev._sum?.loyaltyPointsEarned ?? 0,
        },
        cashiCoinsRewarded: {
          // saved amount
          current: (salesAgg as any)._sum?.cashiCoinsEarned ?? 0,
          prev: (salesAggPrev as any)._sum?.cashiCoinsEarned ?? 0,
        },
        couponsRedeemed: {
          current: couponsRedeemed,
          prev: couponsRedeemedPrev,
        },
      },
    };
  }

  async summary() {
    const [
      shopsTotal,
      shopsApproved,
      shopsPending,
      shopsRejected,
      shopsActive,
      shopsInactive,
      usersTotal,
      usersActive,
      usersInactive,
      customersTotal,
      adminsTotal,
      subadminsTotal,
      superadminsTotal,
      salesAgg,
      couponsTotal,
      couponsDraft,
      couponsActive,
      couponsExpired,
      customerCouponsTotal,
      customerCouponsAssigned,
      customerCouponsRedeemed,
      customerCouponsExpired,
      customersWithCoupons,
      salesWithCoupon,
    ] = await this.prisma.$transaction([
      this.prisma.shop.count(),
      this.prisma.shop.count({ where: { status: ShopStatus.APPROVED } }),
      this.prisma.shop.count({ where: { status: ShopStatus.PENDING } }),
      this.prisma.shop.count({ where: { status: ShopStatus.REJECTED } }),
      this.prisma.shop.count({ where: { isActive: true } }),
      this.prisma.shop.count({ where: { isActive: false } }),

      this.prisma.user.count(),
      this.prisma.user.count({ where: { isActive: true } }),
      this.prisma.user.count({ where: { isActive: false } }),
      this.prisma.user.count({ where: { role: UserRole.USER } }),
      this.prisma.user.count({ where: { role: UserRole.ADMIN } }),
      this.prisma.user.count({ where: { role: UserRole.SUBADMIN } }),
      this.prisma.user.count({ where: { role: UserRole.SUPERADMIN } }),

      this.prisma.sale.aggregate({
        where: { status: SaleStatus.COMPLETED },
        _count: { _all: true },
        _sum: {
          amount: true,
          discountAmount: true,
          loyaltyPointsEarned: true,
          loyaltyPointsRedeemed: true,
        },
      }),

      this.prisma.coupon.count(),
      this.prisma.coupon.count({ where: { status: CouponStatus.DRAFT } }),
      this.prisma.coupon.count({ where: { status: CouponStatus.ACTIVE } }),
      this.prisma.coupon.count({ where: { status: CouponStatus.EXPIRED } }),

      this.prisma.customerCoupon.count(),
      this.prisma.customerCoupon.count({
        where: { status: CustomerCouponStatus.ASSIGNED },
      }),
      this.prisma.customerCoupon.count({
        where: { status: CustomerCouponStatus.REDEEMED },
      }),
      this.prisma.customerCoupon.count({
        where: { status: CustomerCouponStatus.EXPIRED },
      }),
      this.prisma.user.count({ where: { customerCoupons: { some: {} } } }),
      this.prisma.sale.count({
        where: { status: SaleStatus.COMPLETED, appliedCouponId: { not: null } },
      }),
    ]);

    return {
      shops: {
        total: shopsTotal,
        approved: shopsApproved,
        pending: shopsPending,
        rejected: shopsRejected,
        active: shopsActive,
        inactive: shopsInactive,
      },
      users: {
        total: usersTotal,
        active: usersActive,
        inactive: usersInactive,
        customers: customersTotal,
        admins: adminsTotal,
        subadmins: subadminsTotal,
        superadmins: superadminsTotal,
      },
      sales: {
        completedCount: salesAgg._count?._all ?? 0,
        amountTotal: salesAgg._sum?.amount ?? 0,
        discountTotal: salesAgg._sum?.discountAmount ?? 0,
        loyaltyEarnedTotal: salesAgg._sum?.loyaltyPointsEarned ?? 0,
        loyaltyRedeemedTotal: salesAgg._sum?.loyaltyPointsRedeemed ?? 0,
      },
      coupons: {
        total: couponsTotal,
        draft: couponsDraft,
        active: couponsActive,
        expired: couponsExpired,
        customerCouponsTotal,
        customerCouponsAssigned,
        customerCouponsRedeemed,
        customerCouponsExpired,
        customersWithCoupons,
        salesWithCoupon,
      },
    };
  }
}
