import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, LessThan } from 'typeorm';
import { Stream, StreamStatus } from '../modules/streams/entities/stream.entity';
import { StreamAnalytics } from '../modules/streams/entities/stream-analytics.entity';
import { NotificationsService } from '../modules/notifications/notifications.service';

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

  constructor(
    @InjectRepository(Stream)
    private readonly streamRepo: Repository<Stream>,
    @InjectRepository(StreamAnalytics)
    private readonly analyticsRepo: Repository<StreamAnalytics>,
    private readonly notificationsService: NotificationsService,
  ) {}

  /**
   * Auto-end streams that have been "live" for over 8 hours
   * Prevents abandoned streams from staying active indefinitely
   */
  @Cron(CronExpression.EVERY_HOUR)
  async autoEndStaleStreams(): Promise<void> {
    this.logger.log('Checking for stale live streams...');

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

    const staleStreams = await this.streamRepo.find({
      where: {
        status: StreamStatus.LIVE,
        actualStartTime: LessThan(eightHoursAgo),
      },
    });

    if (staleStreams.length === 0) {
      this.logger.log('No stale live streams found');
      return;
    }

    this.logger.warn(`Found ${staleStreams.length} stale live streams - auto-ending`);

    for (const stream of staleStreams) {
      stream.status = StreamStatus.ENDED;
      stream.endedAt = new Date();
      await this.streamRepo.save(stream);

      await this.notificationsService.sendToUser(stream.sellerId, {
        type: 'stream_auto_ended',
        data: {
          streamId: stream.id,
          title: stream.title,
          reason: 'Stream exceeded maximum duration of 8 hours',
          endedAt: new Date().toISOString(),
        },
      });
    }
  }

  /**
   * Clean up old stream analytics data (older than 90 days)
   * Archives to cold storage or deletes based on retention policy
   * Runs daily at 2:00 AM
   */
  @Cron('0 2 * * *')
  async cleanupOldAnalytics(): Promise<void> {
    this.logger.log('Cleaning up old stream analytics...');

    const ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);

    const oldAnalytics = await this.analyticsRepo.find({
      where: {
        createdAt: LessThan(ninetyDaysAgo),
      },
    });

    if (oldAnalytics.length > 0) {
      // Archive to file or delete based on retention policy
      await this.analyticsRepo.remove(oldAnalytics);
      this.logger.log(`Cleaned up ${oldAnalytics.length} old analytics records`);
    }
  }

  /**
   * Mark scheduled streams as missed if they never went live
   * Runs every 30 minutes
   */
  @Cron(CronExpression.EVERY_30_MINUTES)
  async markMissedStreams(): Promise<void> {
    const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000);

    const missedStreams = await this.streamRepo.find({
      where: {
        status: StreamStatus.SCHEDULED,
        scheduledAt: LessThan(twoHoursAgo),
      },
    });

    for (const stream of missedStreams) {
      stream.status = StreamStatus.CANCELLED;
      await this.streamRepo.save(stream);

      this.logger.log(`Marked stream ${stream.id} as missed/cancelled`);
    }
  }

  /**
   * Generate daily stream performance summary
   * Runs at midnight every day
   */
  @Cron('0 0 * * *')
  async generateDailySummary(): Promise<void> {
    this.logger.log('Generating daily stream summary...');

    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: LessThan(today),
      },
    });

    const totalViewers = dailyStreams.reduce((sum, s) => sum + s.viewerCount, 0);
    const totalPurchases = dailyStreams.reduce((sum, s) => sum + s.purchaseCount, 0);

    this.logger.log(`Daily Summary: ${dailyStreams.length} streams, ${totalViewers} viewers, ${totalPurchases} purchases`);
  }
}