import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import type { TransferCategory, TransferCondition } from '@prisma/client';
import { DomainException, LoggerService } from '@modules/shared';
import {
  estimateFurniturePrice,
  type FurniturePriceEstimate,
} from '../../../domain/services/furniture-pricing.service';
import {
  CLAUDE_VISION_SERVICE,
  type IClaudeVisionService,
  type VisionAssessmentResult,
} from '../../../infrastructure/services/claude-vision.service';
import { EstimateFromPhotosCommand, type PhotoEstimateItemInput } from './estimate-from-photos.command';

export interface PhotoEstimateItemResult {
  visionAssessment: VisionAssessmentResult;
  ruleBasedEstimate: {
    estimatedPriceVND: string;
    confidence: number;
    factors: FurniturePriceEstimate['factors'];
  } | null;
  visionAdjustedEstimate: {
    estimatedPriceVND: string;
    confidence: number;
    factors: FurniturePriceEstimate['factors'];
  } | null;
}

export interface PhotoEstimateResult {
  items: PhotoEstimateItemResult[];
  visionAvailable: boolean;
}

@CommandHandler(EstimateFromPhotosCommand)
export class EstimateFromPhotosHandler implements ICommandHandler<EstimateFromPhotosCommand> {
  constructor(
    @Inject(CLAUDE_VISION_SERVICE) private readonly visionService: IClaudeVisionService,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: EstimateFromPhotosCommand): Promise<PhotoEstimateResult> {
    try {
      const visionAvailable = this.visionService.isAvailable();
      const results: PhotoEstimateItemResult[] = [];

      for (const item of command.items) {
        const result = await this.assessItem(item);
        results.push(result);
      }

      return { items: results, visionAvailable };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to estimate from photos: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể ước tính giá từ ảnh');
    }
  }

  private async assessItem(item: PhotoEstimateItemInput): Promise<PhotoEstimateItemResult> {
    // Get Vision assessment
    const visionAssessment = await this.visionService.assessFurnitureCondition({
      imageUrls: item.imageUrls,
      imageBase64: item.imageBase64,
    });

    // Rule-based estimate using user-provided condition (if enough data)
    const ruleBasedEstimate = this.tryRuleBasedEstimate(
      item.category,
      undefined, // no condition override — use default GOOD
      item.originalPriceVND,
      item.purchaseYear,
      item.brand,
    );

    // Vision-adjusted estimate using Vision-assessed condition
    const category = visionAssessment.detectedCategory ?? item.category;
    const brand = visionAssessment.detectedBrand ?? item.brand;
    const visionAdjustedEstimate = this.tryRuleBasedEstimate(
      category,
      visionAssessment.condition,
      item.originalPriceVND,
      item.purchaseYear,
      brand,
    );

    return { visionAssessment, ruleBasedEstimate, visionAdjustedEstimate };
  }

  private tryRuleBasedEstimate(
    category: TransferCategory | undefined,
    condition: TransferCondition | undefined,
    originalPriceVND: number | undefined,
    purchaseYear: number | undefined,
    brand: string | undefined,
  ): PhotoEstimateItemResult['ruleBasedEstimate'] {
    if (!category || !originalPriceVND || !purchaseYear) return null;

    const estimate = estimateFurniturePrice({
      category,
      condition: condition ?? 'GOOD',
      originalPriceVND: BigInt(Math.round(originalPriceVND)),
      purchaseYear,
      brand,
    });

    return {
      estimatedPriceVND: estimate.estimatedPriceVND.toString(),
      confidence: estimate.confidence,
      factors: estimate.factors,
    };
  }
}
