import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { StatisticsAggregationService } from '../../application/services/statistics-aggregation.service';
import { FinancialReportService } from '../../application/services/financial-report.service';
import { AuditLogService } from '../../application/services/audit-log.service';

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

  constructor(
    private readonly statisticsService: StatisticsAggregationService,
    private readonly financialReportService: FinancialReportService,
    private readonly auditLogService: AuditLogService,
  ) {}

  /**
   * Daily statistics aggregation - runs at 00:05 AM Asia/Shanghai
   * 5 minutes past midnight to ensure all previous day data is available
   */
  @Cron('5 0 * * *', {
    name: 'daily-statistics',
    timeZone: 'Asia/Shanghai',
  })
  async aggregateDailyStatistics(): Promise<void> {
    this.logger.log('Starting daily statistics aggregation (scheduled)...');

    try {
      // Calculate for previous day
      const yesterday = new Date();
      yesterday.setDate(yesterday.getDate() - 1);

      await this.statisticsService.aggregateDailyStats(yesterday);

      await this.auditLogService.logSystem(
        'DAILY_STATS_AGGREGATION',
        'DailyStatistics',
        undefined,
        `Aggregated statistics for ${yesterday.toISOString().split('T')[0]}`,
      );

      this.logger.log('Daily statistics aggregation completed');
    } catch (error) {
      this.logger.error('Daily statistics aggregation failed:', error);

      await this.auditLogService.log({
        actorType: 'SYSTEM',
        actorName: 'Scheduler',
        action: 'DAILY_STATS_AGGREGATION',
        entityType: 'DailyStatistics',
        result: 'FAILED',
        errorMessage: error instanceof Error ? error.message : String(error),
      });
    }
  }

  /**
   * Monthly financial report - runs at 02:00 AM on the 1st of each month
   */
  @Cron('0 2 1 * *', {
    name: 'monthly-financial-report',
    timeZone: 'Asia/Shanghai',
  })
  async generateMonthlyReport(): Promise<void> {
    this.logger.log('Starting monthly financial report generation (scheduled)...');

    try {
      // Calculate for previous month
      const now = new Date();
      const previousMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
      const reportMonth = previousMonth.toISOString().slice(0, 7); // YYYY-MM format

      await this.financialReportService.generateMonthlyReport(reportMonth);

      await this.auditLogService.logSystem(
        'MONTHLY_REPORT_GENERATION',
        'MonthlyFinancialReport',
        undefined,
        `Generated financial report for ${reportMonth}`,
      );

      this.logger.log(`Monthly financial report generated for: ${reportMonth}`);
    } catch (error) {
      this.logger.error('Monthly financial report generation failed:', error);

      await this.auditLogService.log({
        actorType: 'SYSTEM',
        actorName: 'Scheduler',
        action: 'MONTHLY_REPORT_GENERATION',
        entityType: 'MonthlyFinancialReport',
        result: 'FAILED',
        errorMessage: error instanceof Error ? error.message : String(error),
      });
    }
  }

  /**
   * Hourly statistics refresh for real-time dashboard
   */
  @Cron(CronExpression.EVERY_HOUR, {
    name: 'hourly-stats-refresh',
    timeZone: 'Asia/Shanghai',
  })
  async refreshTodayStats(): Promise<void> {
    this.logger.log('Refreshing today statistics (hourly)...');

    try {
      await this.statisticsService.refreshTodayStats();
      this.logger.log('Today statistics refresh completed');
    } catch (error) {
      this.logger.error('Today statistics refresh failed:', error);
    }
  }

  /**
   * Manual trigger for daily statistics (for testing or backfill)
   */
  async manualAggregateStats(date: Date): Promise<void> {
    this.logger.log(`Manual statistics aggregation for: ${date.toISOString().split('T')[0]}`);
    await this.statisticsService.aggregateDailyStats(date);
  }

  /**
   * Manual trigger for monthly report (for testing or backfill)
   */
  async manualGenerateReport(reportMonth: string): Promise<void> {
    this.logger.log(`Manual financial report generation for: ${reportMonth}`);
    await this.financialReportService.generateMonthlyReport(reportMonth);
  }

  /**
   * Backfill statistics for a date range
   */
  async backfillStatistics(startDate: Date, endDate: Date): Promise<void> {
    this.logger.log(`Backfilling statistics from ${startDate.toISOString()} to ${endDate.toISOString()}`);

    const current = new Date(startDate);
    while (current <= endDate) {
      try {
        await this.statisticsService.aggregateDailyStats(current);
        this.logger.log(`Backfilled: ${current.toISOString().split('T')[0]}`);
      } catch (error) {
        this.logger.error(`Failed to backfill ${current.toISOString().split('T')[0]}:`, error);
      }
      current.setDate(current.getDate() + 1);
    }

    this.logger.log('Backfill completed');
  }
}
