import * as fs from 'fs';
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Inject, Logger } from '@nestjs/common';
import { type Job } from 'bullmq';
import { REPORT_GENERATION_QUEUE } from '../../application/commands/generate-report/generate-report.handler';
import { ReportType } from '../../domain/enums/report-type.enum';
import { REPORT_REPOSITORY, type IReportRepository } from '../../domain/repositories/report.repository';
import { AI_NARRATIVE_SERVICE, type IAINarrativeService } from '../../domain/services/ai-narrative.service';
import { INFRASTRUCTURE_DATA_SERVICE, type IInfrastructureDataService } from '../../domain/services/infrastructure-data.service';
import { MACRO_DATA_SERVICE, type IMacroDataService } from '../../domain/services/macro-data.service';
import { PDF_GENERATOR_SERVICE, type IPdfGeneratorService } from '../../domain/services/pdf-generator.service';
import { PDF_STORAGE_SERVICE, type IPdfStorageService } from '../../domain/services/pdf-storage.service';

interface GenerateJobData {
  reportId: string;
}

@Processor(REPORT_GENERATION_QUEUE)
export class ReportGenerationProcessor extends WorkerHost {
  private readonly logger = new Logger(ReportGenerationProcessor.name);

  constructor(
    @Inject(REPORT_REPOSITORY) private readonly reportRepo: IReportRepository,
    @Inject(MACRO_DATA_SERVICE) private readonly macroData: IMacroDataService,
    @Inject(INFRASTRUCTURE_DATA_SERVICE) private readonly infraData: IInfrastructureDataService,
    @Inject(AI_NARRATIVE_SERVICE) private readonly aiNarrative: IAINarrativeService,
    @Inject(PDF_GENERATOR_SERVICE) private readonly pdfGenerator: IPdfGeneratorService,
    @Inject(PDF_STORAGE_SERVICE) private readonly pdfStorage: IPdfStorageService,
  ) {
    super();
  }

  async process(job: Job<GenerateJobData>): Promise<void> {
    const { reportId } = job.data;
    this.logger.log(`Processing report generation: ${reportId}`);

    const report = await this.reportRepo.findById(reportId);
    if (!report) {
      this.logger.warn(`Report ${reportId} not found, skipping.`);
      return;
    }

    try {
      const content = await this.generateContent(report.type, report.params);

      // Generate and upload PDF
      let pdfUrl: string | null = null;
      try {
        const pdfPath = await this.pdfGenerator.generatePdf(reportId, content);
        const pdfBuffer = fs.readFileSync(pdfPath);
        pdfUrl = await this.pdfStorage.uploadPdf(pdfBuffer, reportId);
        fs.unlinkSync(pdfPath);
      } catch (pdfErr) {
        this.logger.warn(`PDF generation failed for ${reportId}, completing without PDF: ${pdfErr instanceof Error ? pdfErr.message : 'Unknown'}`);
      }

      report.markReady(content, pdfUrl);
      await this.reportRepo.update(report);
      this.logger.log(`Report ${reportId} generated successfully.`);
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : 'Unknown error';
      this.logger.error(`Report ${reportId} generation failed: ${errMsg}`);
      report.markFailed(errMsg);
      await this.reportRepo.update(report);
      throw error;
    }
  }

  private async generateContent(
    type: string,
    params: Record<string, unknown>,
  ): Promise<Record<string, unknown>> {
    switch (type) {
      case ReportType.INDUSTRIAL_LOCATION:
        return this.generateIndustrialLocationReport(params);
      case ReportType.RESIDENTIAL_MARKET:
        return this.generateResidentialMarketReport(params);
      case ReportType.DISTRICT_ANALYSIS:
        return this.generateDistrictAnalysisReport(params);
      default:
        return this.generateGenericReport(type, params);
    }
  }

  private async generateIndustrialLocationReport(
    params: Record<string, unknown>,
  ): Promise<Record<string, unknown>> {
    const province = params['province'] as string;

    const [macroData, infraProjects] = await Promise.all([
      this.macroData.getByProvince(province, ['gdp', 'fdi', 'population', 'urbanization', 'labor_force', 'avg_wage', 'industrial_output']),
      this.infraData.getByProvince(province),
    ]);

    const macroByIndicator: Record<string, Array<{ period: string; value: number; unit: string }>> = {};
    for (const dp of macroData) {
      const arr = macroByIndicator[dp.indicator] ??= [];
      arr.push({ period: dp.period, value: dp.value, unit: dp.unit });
    }

    const infraSerialized = infraProjects.map((p) => ({
      name: p.name,
      category: p.category,
      status: p.status,
      investmentVND: p.investmentVND?.toString() ?? null,
      completionDate: p.completionDate?.toISOString() ?? null,
    }));

    const dataContext = { province, macroByIndicator, infraProjects: infraSerialized };

    // Generate AI narratives for sections that need analysis
    const [executiveSummary, industrialLandscape, riskAssessment, recommendation] = await Promise.all([
      this.aiNarrative.generateNarrative({
        reportType: ReportType.INDUSTRIAL_LOCATION,
        sectionKey: 'executive_summary',
        sectionTitle: 'Tóm tắt',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.INDUSTRIAL_LOCATION,
        sectionKey: 'industrial_landscape',
        sectionTitle: 'Thị trường KCN',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.INDUSTRIAL_LOCATION,
        sectionKey: 'risk_assessment',
        sectionTitle: 'Đánh giá rủi ro',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.INDUSTRIAL_LOCATION,
        sectionKey: 'recommendation',
        sectionTitle: 'Khuyến nghị đầu tư',
        context: dataContext,
      }),
    ]);

    return {
      reportType: ReportType.INDUSTRIAL_LOCATION,
      province,
      generatedAt: new Date().toISOString(),
      sections: {
        executive_summary: {
          title: 'Tóm tắt',
          content: executiveSummary,
        },
        economic_indicators: {
          title: 'Chỉ số kinh tế',
          data: macroByIndicator,
          charts: {
            gdp_trend: macroByIndicator['gdp'] ?? [],
            fdi_trend: macroByIndicator['fdi'] ?? [],
          },
        },
        demographics: {
          title: 'Dân số & Lao động',
          data: {
            population: macroByIndicator['population'] ?? [],
            urbanization: macroByIndicator['urbanization'] ?? [],
            labor_force: macroByIndicator['labor_force'] ?? [],
            avg_wage: macroByIndicator['avg_wage'] ?? [],
          },
        },
        infrastructure: {
          title: 'Hạ tầng',
          projects: infraSerialized,
          summary: {
            total: infraProjects.length,
            byCategory: this.groupBy(infraProjects as unknown as Array<Record<string, unknown>>, 'category'),
            byStatus: this.groupBy(infraProjects as unknown as Array<Record<string, unknown>>, 'status'),
          },
        },
        industrial_landscape: {
          title: 'Thị trường KCN',
          content: industrialLandscape,
        },
        risk_assessment: {
          title: 'Đánh giá rủi ro',
          content: riskAssessment,
        },
        recommendation: {
          title: 'Khuyến nghị đầu tư',
          content: recommendation,
        },
      },
    };
  }

  private async generateResidentialMarketReport(
    params: Record<string, unknown>,
  ): Promise<Record<string, unknown>> {
    const city = params['city'] as string;
    const period = params['period'] as string;

    const macroData = await this.macroData.getByProvince(city, ['gdp', 'cpi', 'mortgage_rate', 'fdi', 'population']);

    const macroByIndicator: Record<string, Array<{ period: string; value: number; unit: string }>> = {};
    for (const dp of macroData) {
      const arr = macroByIndicator[dp.indicator] ??= [];
      arr.push({ period: dp.period, value: dp.value, unit: dp.unit });
    }

    const dataContext = { city, period, macroByIndicator };

    const [executiveSummary, marketOverview, priceAnalysis, supplyDemand, forecast, recommendation] = await Promise.all([
      this.aiNarrative.generateNarrative({
        reportType: ReportType.RESIDENTIAL_MARKET,
        sectionKey: 'executive_summary',
        sectionTitle: 'Tóm tắt thị trường',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.RESIDENTIAL_MARKET,
        sectionKey: 'market_overview',
        sectionTitle: 'Tổng quan',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.RESIDENTIAL_MARKET,
        sectionKey: 'price_analysis',
        sectionTitle: 'Phân tích giá',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.RESIDENTIAL_MARKET,
        sectionKey: 'supply_demand',
        sectionTitle: 'Cung cầu',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.RESIDENTIAL_MARKET,
        sectionKey: 'forecast',
        sectionTitle: 'Dự báo',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.RESIDENTIAL_MARKET,
        sectionKey: 'recommendation',
        sectionTitle: 'Khuyến nghị',
        context: dataContext,
      }),
    ]);

    return {
      reportType: ReportType.RESIDENTIAL_MARKET,
      city,
      period,
      generatedAt: new Date().toISOString(),
      sections: {
        executive_summary: {
          title: 'Tóm tắt thị trường',
          content: executiveSummary,
        },
        market_overview: {
          title: 'Tổng quan',
          content: marketOverview,
        },
        price_analysis: {
          title: 'Phân tích giá',
          content: priceAnalysis,
        },
        supply_demand: {
          title: 'Cung cầu',
          content: supplyDemand,
        },
        macro_impact: {
          title: 'Tác động vĩ mô',
          data: macroByIndicator,
        },
        forecast: {
          title: 'Dự báo',
          content: forecast,
        },
        recommendation: {
          title: 'Khuyến nghị',
          content: recommendation,
        },
      },
    };
  }

  private async generateDistrictAnalysisReport(
    params: Record<string, unknown>,
  ): Promise<Record<string, unknown>> {
    const city = params['city'] as string;
    const district = params['district'] as string;

    const dataContext = { city, district };

    const [executiveSummary, marketData, neighborhood, infrastructure, recommendation] = await Promise.all([
      this.aiNarrative.generateNarrative({
        reportType: ReportType.DISTRICT_ANALYSIS,
        sectionKey: 'executive_summary',
        sectionTitle: 'Tóm tắt',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.DISTRICT_ANALYSIS,
        sectionKey: 'market_overview',
        sectionTitle: 'Dữ liệu thị trường',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.DISTRICT_ANALYSIS,
        sectionKey: 'supply_demand',
        sectionTitle: 'Khu vực lân cận',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.DISTRICT_ANALYSIS,
        sectionKey: 'industrial_landscape',
        sectionTitle: 'Hạ tầng',
        context: dataContext,
      }),
      this.aiNarrative.generateNarrative({
        reportType: ReportType.DISTRICT_ANALYSIS,
        sectionKey: 'recommendation',
        sectionTitle: 'Khuyến nghị',
        context: dataContext,
      }),
    ]);

    return {
      reportType: ReportType.DISTRICT_ANALYSIS,
      city,
      district,
      generatedAt: new Date().toISOString(),
      sections: {
        executive_summary: {
          title: 'Tóm tắt',
          content: executiveSummary,
        },
        market_data: { title: 'Dữ liệu thị trường', content: marketData },
        neighborhood: { title: 'Khu vực lân cận', content: neighborhood },
        infrastructure: { title: 'Hạ tầng', content: infrastructure },
        recommendation: { title: 'Khuyến nghị', content: recommendation },
      },
    };
  }

  private async generateGenericReport(
    type: string,
    params: Record<string, unknown>,
  ): Promise<Record<string, unknown>> {
    const summary = await this.aiNarrative.generateNarrative({
      reportType: type,
      sectionKey: 'executive_summary',
      sectionTitle: 'Tóm tắt',
      context: params,
    });

    return {
      reportType: type,
      params,
      generatedAt: new Date().toISOString(),
      sections: {
        executive_summary: {
          title: 'Tóm tắt',
          content: summary,
        },
      },
    };
  }

  private groupBy(items: Array<{ [key: string]: unknown }>, key: string): Record<string, number> {
    const result: Record<string, number> = {};
    for (const item of items) {
      const val = String(item[key]);
      result[val] = (result[val] ?? 0) + 1;
    }
    return result;
  }
}
