import { Injectable, Inject, Logger } from '@nestjs/common';
import {
  IReportDefinitionRepository,
  IReportSnapshotRepository,
  REPORT_DEFINITION_REPOSITORY,
  REPORT_SNAPSHOT_REPOSITORY,
} from '../../domain/repositories';
import { ReportDefinition } from '../../domain/aggregates/report-definition';
import { ReportSnapshot } from '../../domain/aggregates/report-snapshot';
import { ReportType, ReportPeriod } from '../../domain/value-objects';

export interface ReportDefinitionDto {
  id: string;
  reportType: string;
  reportName: string;
  reportCode: string;
  description: string;
  parameters: Record<string, any>;
  scheduleCron: string | null;
  scheduleEnabled: boolean;
  outputFormats: string[];
  isActive: boolean;
  lastGeneratedAt: Date | null;
}

export interface ReportSnapshotDto {
  id: string;
  reportType: string;
  reportCode: string;
  reportPeriod: string;
  periodKey: string;
  rowCount: number;
  summary: Record<string, any>;
  periodStartAt: Date;
  periodEndAt: Date;
  generatedAt: Date;
}

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

  constructor(
    @Inject(REPORT_DEFINITION_REPOSITORY)
    private readonly definitionRepo: IReportDefinitionRepository,
    @Inject(REPORT_SNAPSHOT_REPOSITORY)
    private readonly snapshotRepo: IReportSnapshotRepository,
  ) {}

  async getReportDefinitions(): Promise<ReportDefinitionDto[]> {
    const definitions = await this.definitionRepo.findActive();
    return definitions.map(this.mapDefinitionToDto);
  }

  async getReportDefinitionByCode(
    code: string,
  ): Promise<ReportDefinitionDto | null> {
    const definition = await this.definitionRepo.findByCode(code);
    return definition ? this.mapDefinitionToDto(definition) : null;
  }

  async getReportSnapshots(reportCode: string): Promise<ReportSnapshotDto[]> {
    const snapshots = await this.snapshotRepo.findByCode(reportCode);
    return snapshots.map(this.mapSnapshotToDto);
  }

  async getLatestSnapshot(reportCode: string): Promise<ReportSnapshotDto | null> {
    const snapshot = await this.snapshotRepo.findLatestByCode(reportCode);
    return snapshot ? this.mapSnapshotToDto(snapshot) : null;
  }

  async getSnapshotsByPeriod(period: ReportPeriod): Promise<ReportSnapshotDto[]> {
    const snapshots = await this.snapshotRepo.findByPeriod(period);
    return snapshots.map(this.mapSnapshotToDto);
  }

  private mapDefinitionToDto(definition: ReportDefinition): ReportDefinitionDto {
    return {
      id: definition.id?.toString() || '',
      reportType: definition.reportType,
      reportName: definition.reportName,
      reportCode: definition.reportCode,
      description: definition.description,
      parameters: definition.parameters,
      scheduleCron: definition.schedule?.cronExpression || null,
      scheduleEnabled: definition.schedule?.enabled || false,
      outputFormats: definition.outputFormats,
      isActive: definition.isActive,
      lastGeneratedAt: definition.lastGeneratedAt,
    };
  }

  private mapSnapshotToDto(snapshot: ReportSnapshot): ReportSnapshotDto {
    return {
      id: snapshot.id?.toString() || '',
      reportType: snapshot.reportType,
      reportCode: snapshot.reportCode,
      reportPeriod: snapshot.reportPeriod,
      periodKey: snapshot.periodKey,
      rowCount: snapshot.rowCount,
      summary: snapshot.snapshotData.summary,
      periodStartAt: snapshot.periodStartAt,
      periodEndAt: snapshot.periodEndAt,
      generatedAt: snapshot.generatedAt,
    };
  }
}
