import { type PropertyType } from '@prisma/client';
import { type Comparable } from '../../domain/services/avm-service';

const DEFAULT_RADIUS_METERS = 2000;

export interface RawComparable {
  property_id: string;
  address: string;
  district: string;
  price_vnd: bigint;
  price_per_m2: number;
  area_m2: number;
  property_type: PropertyType;
  distance_meters: number;
  published_at: Date;
}

/** Map a raw SQL comparable row to the domain Comparable DTO. */
export function toComparableDto(raw: RawComparable): Comparable {
  return {
    propertyId: raw.property_id,
    address: raw.address,
    district: raw.district,
    priceVND: raw.price_vnd.toString(),
    pricePerM2: raw.price_per_m2,
    areaM2: raw.area_m2,
    propertyType: raw.property_type,
    distanceMeters: Math.round(raw.distance_meters),
    soldAt: raw.published_at.toISOString(),
  };
}

/**
 * Distance-weighted average price calculation.
 * Closer properties carry more weight in the estimate.
 */
export function calculateWeightedPrice(
  comparables: RawComparable[],
  _areaM2: number,
  _propertyType: PropertyType | undefined,
  _yearBuilt: number | null,
  _floor: number | null,
  _totalFloors: number | null,
): { pricePerM2: number; confidence: number } {
  let totalWeight = 0;
  let weightedSum = 0;

  for (const comp of comparables) {
    const distance = Math.max(comp.distance_meters, 1);
    const weight = 1 / distance;
    weightedSum += comp.price_per_m2 * weight;
    totalWeight += weight;
  }

  const pricePerM2 = totalWeight > 0 ? weightedSum / totalWeight : 0;

  // Confidence based on number of comparables and distance spread
  const maxComparables = 15;
  const countFactor = Math.min(comparables.length / maxComparables, 1);
  const avgDistance =
    comparables.reduce((sum, c) => sum + c.distance_meters, 0) / comparables.length;
  const distanceFactor = Math.max(0, 1 - avgDistance / DEFAULT_RADIUS_METERS);
  const confidence = Math.round((countFactor * 0.6 + distanceFactor * 0.4) * 100) / 100;

  return { pricePerM2: Math.round(pricePerM2), confidence };
}
