import { Inject, Injectable } from '@nestjs/common';
import { PrismaService, LoggerService } from '@modules/shared';
import {
  IAVMService,
  type AVMParams,
  type ValuationResult,
  type Comparable,
} from '../../domain/services/avm-service';
import {
  AI_SERVICE_CLIENT,
  IAiServiceClient,
  type AiPredictRequest,
} from './ai-service.client';
import { PrismaAVMService } from './prisma-avm.service';

@Injectable()
export class HttpAVMService implements IAVMService {
  constructor(
    @Inject(AI_SERVICE_CLIENT) private readonly aiClient: IAiServiceClient,
    private readonly fallback: PrismaAVMService,
    private readonly prisma: PrismaService,
    private readonly logger: LoggerService,
  ) {}

  async estimateValue(params: AVMParams): Promise<ValuationResult> {
    try {
      return await this.estimateViaAi(params);
    } catch (err) {
      this.logger.warn(
        `AI AVM service unavailable, falling back to comparables-based estimation: ${(err as Error).message}`,
        'HttpAVMService',
      );
      return this.fallback.estimateValue(params);
    }
  }

  async getComparables(propertyId: string, radiusMeters: number): Promise<Comparable[]> {
    return this.fallback.getComparables(propertyId, radiusMeters);
  }

  private async estimateViaAi(params: AVMParams): Promise<ValuationResult> {
    const propertyData = params.propertyId
      ? await this.getPropertyDetails(params.propertyId)
      : null;

    const request: AiPredictRequest = {
      area: params.areaM2 ?? propertyData?.areaM2 ?? 0,
      district: propertyData?.district ?? '',
      city: propertyData?.city ?? '',
      property_type: (params.propertyType ?? propertyData?.propertyType ?? 'house').toLowerCase(),
      bedrooms: propertyData?.bedrooms ?? 0,
      bathrooms: propertyData?.bathrooms ?? 0,
      floors: propertyData?.floors ?? 0,
      frontage: 0,
      road_width: 0,
      year_built: params.yearBuilt ?? propertyData?.yearBuilt,
      has_legal_paper: propertyData?.hasLegalPaper ?? true,
    };

    const aiResult = await this.aiClient.predict(request);

    // Also fetch comparables from the local PostGIS service for context
    let comparables: Comparable[] = [];
    try {
      if (params.propertyId) {
        comparables = await this.fallback.getComparables(params.propertyId, 2000);
      }
    } catch {
      // Comparables are supplementary — don't fail the valuation
    }

    return {
      estimatedPrice: Math.round(aiResult.estimated_price_vnd).toString(),
      confidence: aiResult.confidence,
      pricePerM2: Math.round(aiResult.price_per_m2),
      comparables,
      modelVersion: 'ai-service-v1.0',
    };
  }

  private async getPropertyDetails(propertyId: string) {
    const row = await this.prisma.property.findUnique({
      where: { id: propertyId },
      select: {
        areaM2: true,
        district: true,
        city: true,
        propertyType: true,
        bedrooms: true,
        bathrooms: true,
        floors: true,
        yearBuilt: true,
        legalStatus: true,
      },
    });

    if (!row) return null;

    return {
      areaM2: row.areaM2,
      district: row.district,
      city: row.city,
      propertyType: row.propertyType,
      bedrooms: row.bedrooms ?? 0,
      bathrooms: row.bathrooms ?? 0,
      floors: row.floors ?? 0,
      yearBuilt: row.yearBuilt,
      hasLegalPaper: row.legalStatus === 'SO_DO' || row.legalStatus === 'SO_HONG',
    };
  }
}
