import { Injectable, Inject, Logger, NotFoundException } from '@nestjs/common';
import { Report, ReportType, ReportStatus } from '../../domain/entities/report.entity';
import {
  REPORT_REPOSITORY,
  IReportRepository,
} from '../../domain/repositories/report.repository.interface';

@Injectable()
export class AdminReportsService {
  private readonly logger = new Logger('AdminReportsService');

  constructor(
    @Inject(REPORT_REPOSITORY)
    private readonly reportRepo: IReportRepository,
  ) {}

  /**
   * List all reports with pagination.
   */
  async listReports(page: number, limit: number, type?: string) {
    const [items, total] = await this.reportRepo.findAndCount({
      type: type as ReportType | undefined,
      page,
      limit,
    });
    return { items, total, page, limit, totalPages: Math.ceil(total / limit) };
  }

  /**
   * Trigger report generation.
   * Creates a report record in PENDING status, then simulates generation.
   */
  async generateReport(
    dto: { type: ReportType; period?: string },
    generatedBy: string,
  ): Promise<Report> {
    const period = dto.period || this.getDefaultPeriod(dto.type);
    const title = this.buildTitle(dto.type, period);

    const report = this.reportRepo.create({
      type: dto.type,
      title,
      period,
      status: ReportStatus.PENDING,
      generatedBy,
    });
    const saved = await this.reportRepo.save(report);

    // Simulate async report generation
    // In production, this would dispatch to a job queue (Bull/BullMQ)
    this.generateReportAsync(saved.id).catch((err) => {
      this.logger.error(
        `Report generation failed for ${saved.id}: ${err.message}`,
      );
    });

    return saved;
  }

  /**
   * Get report by ID for download.
   */
  async getReportForDownload(id: string): Promise<Report> {
    const report = await this.reportRepo.findById(id);
    if (!report) {
      throw new NotFoundException(`Report ${id} not found`);
    }
    return report;
  }

  /**
   * Simulate async report generation.
   * In a real system, this would query data, build CSV/PDF, upload to S3, etc.
   */
  private async generateReportAsync(reportId: string): Promise<void> {
    // Simulate processing time
    await new Promise((resolve) => setTimeout(resolve, 2000));

    const report = await this.reportRepo.findById(reportId);
    if (!report) return;

    try {
      // Mock: generate a file URL
      const fileName = `report_${report.type}_${report.period.replace(/\s+/g, '_')}_${Date.now()}.csv`;
      report.fileUrl = `/reports/${fileName}`;
      report.status = ReportStatus.GENERATED;
      report.generatedAt = new Date();
      await this.reportRepo.save(report);
      this.logger.log(`Report ${reportId} generated: ${report.fileUrl}`);
    } catch (error) {
      report.status = ReportStatus.FAILED;
      await this.reportRepo.save(report);
      throw error;
    }
  }

  private getDefaultPeriod(type: ReportType): string {
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0');

    switch (type) {
      case ReportType.DAILY:
        return `${year}-${month}-${String(now.getDate()).padStart(2, '0')}`;
      case ReportType.MONTHLY:
        return `${year}-${month}`;
      case ReportType.QUARTERLY: {
        const quarter = Math.ceil((now.getMonth() + 1) / 3);
        return `${year}-Q${quarter}`;
      }
      case ReportType.ANNUAL:
        return `${year}`;
      default:
        return `${year}-${month}`;
    }
  }

  private buildTitle(type: ReportType, period: string): string {
    const typeLabel = type.charAt(0).toUpperCase() + type.slice(1);
    return `${typeLabel} Financial Report - ${period}`;
  }
}
