import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ScannerProvider } from './providers/scanner.provider';
import * as sharp from 'sharp';
import { performance } from 'perf_hooks';
import { AnalysisResponse, IndustrialSummary } from './interfaces/palm-analysis.interface';
import { History } from './entities/history.entity';
import { MPOB_CLASSES, HEALTH_ALERT_CLASSES } from './constants/mpob-standards';

@Injectable()
export class PalmOilService {
  constructor(
    private readonly scanner: ScannerProvider,
    @InjectRepository(History)
    private readonly historyRepository: Repository<History>,
  ) { }

  async analyzeImage(imageBuffer: Buffer, originalFilename: string = 'unknown.jpg'): Promise<AnalysisResponse> {
    const processingStart = performance.now();

    // 1. Get original image dimensions
    const metadata = await sharp(imageBuffer).metadata();
    const originalWidth = metadata.width || 640;
    const originalHeight = metadata.height || 640;

    // 2. Preprocess
    const tensor = await this.scanner.preprocess(imageBuffer);

    // 3. Inference with timing
    const inferenceStart = performance.now();
    const outputTensor = await this.scanner.inference(tensor);
    const inferenceMs = performance.now() - inferenceStart;

    // 4. Post-process
    const detections = await this.scanner.postprocess(
      outputTensor,
      originalWidth,
      originalHeight,
    );

    // 5. Generate Industrial Summary
    const industrialSummary: IndustrialSummary = {};
    // Initialize with 0 for all known classes
    Object.values(MPOB_CLASSES).forEach((cls) => {
      industrialSummary[cls] = 0;
    });

    detections.forEach((det) => {
      // Re-verify health alert flag just in case
      det.is_health_alert = HEALTH_ALERT_CLASSES.includes(det.class);
      industrialSummary[det.class] = (industrialSummary[det.class] || 0) + 1;
    });

    // console.log('📊 Industrial Summary:', industrialSummary);

    const processingMs = performance.now() - processingStart;
    const archiveId = `palm_${Date.now()}_${Math.floor(Math.random() * 1000)}`;

    // 6. Persistence to SQLite
    const history = new History();
    history.archive_id = archiveId;
    history.filename = originalFilename;
    history.total_count = detections.length;
    history.industrial_summary = industrialSummary;

    // Ensure detections is an array of objects, not a leaked JSON string
    history.detections = Array.isArray(detections) ? detections : [];

    history.inference_ms = parseFloat(inferenceMs.toFixed(2));
    history.processing_ms = parseFloat(processingMs.toFixed(2));

    await this.historyRepository.save(history);

    return {
      status: 'success',
      current_threshold: 0.25,
      total_count: detections.length,
      industrial_summary: industrialSummary,
      detections: history.detections,
      image_data: `data:image/jpeg;base64,${imageBuffer.toString('base64')}`, // Pass the image back
      inference_ms: history.inference_ms,
      processing_ms: history.processing_ms,
      archive_id: archiveId,
    };
  }

  async getHistory(): Promise<History[]> {
    // Return objects directly; TypeORM simple-json handles parsing
    return this.historyRepository.find({
      order: {
        created_at: 'DESC',
      },
      take: 50,
    });
  }
}
