import { Injectable, Inject } from '@nestjs/common';
import { COUPON_REPOSITORY, ICouponRepository } from '../../domain/repositories/coupon.repository.interface';
import { ISSUER_REPOSITORY, IIssuerRepository } from '../../domain/repositories/issuer.repository.interface';
import { CouponStatus } from '../../domain/entities/coupon.entity';

export interface CouponStats {
  totalCoupons: number;
  totalSupply: number;
  totalSold: number;
  totalRemaining: number;
  circulationRate: number;
  byStatus: Record<string, number>;
}

export interface CouponsByIssuer {
  issuerId: string;
  companyName: string;
  couponCount: number;
  totalSupply: number;
  totalSold: number;
  totalFaceValue: number;
}

export interface CouponsByCategory {
  category: string;
  couponCount: number;
  totalSupply: number;
  totalSold: number;
  avgPrice: number;
}

export interface LifecyclePipeline {
  minted: number;
  listed: number;
  sold: number;
  inCirculation: number;
  redeemed: number;
  expired: number;
  recalled: number;
  totalSold: number;
  totalRedeemed: number;
}

export interface RedemptionRateTrend {
  month: string;
  totalIssued: number;
  totalSold: number;
  redemptionRate: number;
}

export interface DiscountDistribution {
  range: string;
  count: number;
  avgDiscount: number;
}

@Injectable()
export class AdminCouponAnalyticsService {
  constructor(
    @Inject(COUPON_REPOSITORY)
    private readonly couponRepo: ICouponRepository,
    @Inject(ISSUER_REPOSITORY)
    private readonly issuerRepo: IIssuerRepository,
  ) {}

  /**
   * Aggregate coupon supply, sold, remaining, and circulation metrics.
   */
  async getCouponStats(): Promise<CouponStats> {
    const aggregate = await this.couponRepo.getAggregateStats();
    const circulationRate =
      aggregate.totalSupply > 0
        ? Math.round((aggregate.totalSold / aggregate.totalSupply) * 10000) / 100
        : 0;

    const statusCounts = await this.couponRepo.getStatusCounts();
    const byStatus: Record<string, number> = {};
    statusCounts.forEach((row) => {
      byStatus[row.status] = row.count;
    });

    return {
      totalCoupons: aggregate.totalCoupons,
      totalSupply: aggregate.totalSupply,
      totalSold: aggregate.totalSold,
      totalRemaining: aggregate.totalRemaining,
      circulationRate,
      byStatus,
    };
  }

  /**
   * Distribution of coupons grouped by issuer.
   */
  async getCouponsByIssuer(): Promise<CouponsByIssuer[]> {
    const raw = await this.couponRepo.getCouponsByIssuer();
    const issuerIds = raw.map((r) => r.issuerId);
    const issuers = await this.issuerRepo.findByIds(issuerIds);
    const issuerMap = new Map(issuers.map((i) => [i.id, i.companyName]));

    return raw.map((row) => ({
      issuerId: row.issuerId,
      companyName: issuerMap.get(row.issuerId) || 'Unknown',
      couponCount: row.couponCount,
      totalSupply: row.totalSupply,
      totalSold: row.totalSold,
      totalFaceValue: row.totalFaceValue,
    }));
  }

  /**
   * Distribution of coupons grouped by category.
   */
  async getCouponsByCategory(): Promise<CouponsByCategory[]> {
    return this.couponRepo.getCouponsByCategory();
  }

  /**
   * Lifecycle pipeline: counts at each status stage.
   */
  async getLifecycle(): Promise<LifecyclePipeline> {
    const statusCounts = await this.couponRepo.getStatusCounts();
    const countMap: Record<string, number> = {};
    statusCounts.forEach((row) => {
      countMap[row.status] = row.count;
    });

    const totalSold = await this.couponRepo.getTotalSold();
    const totalRedeemed = await this.couponRepo.getTotalSoldByStatuses([
      CouponStatus.REDEEMED,
    ]);

    return {
      minted: countMap[CouponStatus.MINTED] || 0,
      listed: countMap[CouponStatus.LISTED] || 0,
      sold: countMap[CouponStatus.SOLD] || 0,
      inCirculation: countMap[CouponStatus.IN_CIRCULATION] || 0,
      redeemed: countMap[CouponStatus.REDEEMED] || 0,
      expired: countMap[CouponStatus.EXPIRED] || 0,
      recalled: countMap[CouponStatus.RECALLED] || 0,
      totalSold,
      totalRedeemed,
    };
  }

  /**
   * Monthly redemption rate trend.
   */
  async getRedemptionRate(): Promise<RedemptionRateTrend[]> {
    const raw = await this.couponRepo.getRedemptionRateTrend();
    return raw.map((row) => ({
      month: row.month,
      totalIssued: row.totalIssued,
      totalSold: row.totalSold,
      redemptionRate:
        row.totalIssued > 0
          ? Math.round((row.totalSold / row.totalIssued) * 10000) / 100
          : 0,
    }));
  }

  /**
   * Secondary market discount distribution (price vs face value).
   */
  async getDiscountDistribution(): Promise<DiscountDistribution[]> {
    return this.couponRepo.getDiscountDistribution();
  }
}
