import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Between } from 'typeorm';
import { SalesMetric } from '../modules/analytics/entities/sales-metric.entity';
import { StreamMetric } from '../modules/analytics/entities/stream-metric.entity';
import { Transaction, TransactionStatus } from '../modules/payments/entities/transaction.entity';
import { Stream, StreamStatus } from '../modules/streams/entities/stream.entity';

@Injectable()
export class AnalyticsAggregatorCron {
  private readonly logger = new Logger(AnalyticsAggregatorCron.name);

  constructor(
    @InjectRepository(SalesMetric)
    private readonly salesMetricRepo: Repository<SalesMetric>,
    @InjectRepository(StreamMetric)
    private readonly streamMetricRepo: Repository<StreamMetric>,
    @InjectRepository(Transaction)
    private readonly transactionRepo: Repository<Transaction>,
    @InjectRepository(Stream)
    private readonly streamRepo: Repository<Stream>,
  ) {}

  /**
   * Aggregate hourly sales metrics
   * Runs every hour
   */
  @Cron(CronExpression.EVERY_HOUR)
  async aggregateHourlySales(): Promise<void> {
    this.logger.log('Aggregating hourly sales metrics...');

    const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
    const now = new Date();

    const hourlyTransactions = await this.transactionRepo.find({
      where: {
        status: TransactionStatus.COMPLETED,
        createdAt: Between(oneHourAgo, now),
      },
    });

    if (hourlyTransactions.length === 0) {
      this.logger.log('No transactions in the last hour');
      return;
    }

    const totalRevenue = hourlyTransactions.reduce((sum, t) => sum + Number(t.totalAmount), 0);
    const totalPlatformFees = hourlyTransactions.reduce((sum, t) => sum + Number(t.platformFee), 0);

    const metric = this.salesMetricRepo.create({
      period: 'hourly',
      startTime: oneHourAgo,
      endTime: now,
      totalRevenue,
      totalPlatformFees,
      transactionCount: hourlyTransactions.length,
      averageOrderValue: totalRevenue / hourlyTransactions.length,
    });

    await this.salesMetricRepo.save(metric);
    this.logger.log(`Hourly sales aggregated: $${totalRevenue.toFixed(2)} from ${hourlyTransactions.length} transactions`);
  }

  /**
   * Aggregate daily stream metrics
   * Runs every day at 1:00 AM
   */
  @Cron('0 1 * * *')
  async aggregateDailyStreams(): Promise<void> {
    this.logger.log('Aggregating daily stream metrics...');

    const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);
    const today = new Date();

    const dailyStreams = await this.streamRepo.find({
      where: {
        status: StreamStatus.ENDED,
        endedAt: Between(yesterday, today),
      },
    });

    const totalViewers = dailyStreams.reduce((sum, s) => sum + s.viewerCount, 0);
    const totalPurchases = dailyStreams.reduce((sum, s) => sum + s.purchaseCount, 0);
    const avgDuration = dailyStreams.length > 0
      ? dailyStreams.reduce((sum, s) => {
          const duration = s.endedAt && s.actualStartTime
            ? new Date(s.endedAt).getTime() - new Date(s.actualStartTime).getTime()
            : 0;
          return sum + duration;
        }, 0) / dailyStreams.length / 1000 / 60 // minutes
      : 0;

    const metric = this.streamMetricRepo.create({
      period: 'daily',
      date: yesterday,
      totalStreams: dailyStreams.length,
      totalViewers,
      totalPurchases,
      averageDuration: Math.round(avgDuration),
      conversionRate: totalViewers > 0 ? (totalPurchases / totalViewers) * 100 : 0,
    });

    await this.streamMetricRepo.save(metric);
    this.logger.log(`Daily streams aggregated: ${dailyStreams.length} streams, ${totalViewers} viewers`);
  }

  /**
   * Weekly analytics rollup
   * Runs every Monday at 4:00 AM
   */
  @Cron('0 4 * * 1')
  async aggregateWeeklyMetrics(): Promise<void> {
    this.logger.log('Generating weekly analytics rollup...');

    const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
    const now = new Date();

    const weeklyTransactions = await this.transactionRepo.find({
      where: {
        status: TransactionStatus.COMPLETED,
        createdAt: Between(weekAgo, now),
      },
    });

    const totalRevenue = weeklyTransactions.reduce((sum, t) => sum + Number(t.totalAmount), 0);

    this.logger.log(`Weekly rollup: $${totalRevenue.toFixed(2)} revenue from ${weeklyTransactions.length} orders`);
  }

  /**
   * Monthly analytics report generation
   * Runs on the 1st of every month at 5:00 AM
   */
  @Cron('0 5 1 * *')
  async generateMonthlyReport(): Promise<void> {
    this.logger.log('Generating monthly analytics report...');

    const monthAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
    const now = new Date();

    // Aggregate monthly metrics for admin dashboard
    const monthlyTransactions = await this.transactionRepo.find({
      where: {
        status: TransactionStatus.COMPLETED,
        createdAt: Between(monthAgo, now),
      },
    });

    const totalRevenue = monthlyTransactions.reduce((sum, t) => sum + Number(t.totalAmount), 0);
    const totalPlatformFees = monthlyTransactions.reduce((sum, t) => sum + Number(t.platformFee), 0);

    this.logger.log(`Monthly report: $${totalRevenue.toFixed(2)} revenue, $${totalPlatformFees.toFixed(2)} platform fees`);
  }
}