import { apiClient } from './api-client';

/**
 * Backend `/analytics/*` endpoints are wrapped by `CacheMetaInterceptor`,
 * returning `{ data: T, cacheMeta: {...} }`. This helper unwraps so callers
 * receive plain `T` (the cacheMeta field is currently unused on the client).
 */
interface CacheMetaEnvelope<T> {
  data: T;
  cacheMeta: { cachedAt: string | null; nextRefreshAt: string | null; source: string };
}

async function unwrap<T>(p: Promise<CacheMetaEnvelope<T> | T>): Promise<T> {
  const raw = await p;
  if (raw && typeof raw === 'object' && 'data' in raw && 'cacheMeta' in raw) {
    return (raw as CacheMetaEnvelope<T>).data;
  }
  return raw as T;
}

export interface MarketReportDistrict {
  district: string;
  city: string;
  propertyType: string;
  period: string;
  medianPrice: string;
  avgPriceM2: number;
  totalListings: number;
  daysOnMarket: number;
  inventoryLevel: number;
  absorptionRate: number | null;
  yoyChange: number | null;
}

export interface MarketReportResponse {
  city: string;
  period: string;
  districts: MarketReportDistrict[];
}

export interface HeatmapDataPoint {
  district: string;
  city: string;
  avgPriceM2: number;
  totalListings: number;
  medianPrice: string;
}

export interface HeatmapResponse {
  city: string;
  period: string;
  dataPoints: HeatmapDataPoint[];
}

export interface PriceTrendPoint {
  period: string;
  medianPrice: string;
  avgPriceM2: number;
  totalListings: number;
}

export interface PriceTrendResponse {
  district: string;
  city: string;
  propertyType: string;
  trend: PriceTrendPoint[];
}

export interface DistrictStats {
  district: string;
  city: string;
  propertyType: string;
  medianPrice: string;
  avgPriceM2: number;
  totalListings: number;
  daysOnMarket: number;
  inventoryLevel: number;
  absorptionRate: number | null;
  yoyChange: number | null;
}

export interface DistrictStatsResponse {
  city: string;
  period: string;
  districts: DistrictStats[];
}

export type NearbyPOICategory =
  | 'school'
  | 'hospital'
  | 'transit'
  | 'shopping'
  | 'restaurant'
  | 'park';

export interface NearbyPOI {
  id: string;
  name: string;
  type: string;
  category: NearbyPOICategory;
  lat: number;
  lng: number;
  distance: number;
  address: string | null;
}

export interface NearbyPOIsResponse {
  pois: NearbyPOI[];
  center: { lat: number; lng: number };
}

export type AiConfidence = 'low' | 'medium' | 'high';

export interface ListingAiValuation {
  estimateVND: number;
  lowVND: number;
  highVND: number;
  confidence: AiConfidence;
  rationale: string;
}

export interface ListingAiAdviceBody {
  summary: string;
  pros: string[];
  cons: string[];
  suitableFor: string[];
}

export interface ListingAiAdvice {
  valuation: ListingAiValuation;
  advice: ListingAiAdviceBody;
  model: string;
  cacheHit: boolean;
  cacheUsage?: {
    input: number;
    cacheCreation: number;
    cacheRead: number;
    output: number;
  };
}

/** Project AI advice — same advice block as listings but no valuation. */
export interface ProjectAiAdvice {
  advice: ListingAiAdviceBody;
  model: string;
  cacheHit: boolean;
  cacheUsage?: {
    input: number;
    cacheCreation: number;
    cacheRead: number;
    output: number;
  };
}

/* ------------------------------------------------------------------ */
/*  Market Snapshot                                                    */
/* ------------------------------------------------------------------ */

export interface PriceChangePct {
  d1: number;
  d7: number;
  d30: number;
}

export interface MarketSnapshotResponse {
  city: string;
  propertyType?: string;
  activeCount: number;
  avgPrice: number;
  medianPrice: number;
  priceChangePct: PriceChangePct;
  avgPricePerM2: number;
  daysOnMarket: number;
  newListings24h: number;
  cachedAt: string | null;
  nextRefreshAt: string | null;
}

/* ------------------------------------------------------------------ */
/*  Price Movers                                                       */
/* ------------------------------------------------------------------ */

export interface PriceMoverItem {
  districtId: string;
  name: string;
  currentAvgPrice: number;
  previousAvgPrice: number;
  changePct: number;
  sampleSize: number;
}

export interface PriceMoversResponse {
  direction: 'up' | 'down';
  period: string;
  level: string;
  limit: number;
  movers: PriceMoverItem[];
}

/* ------------------------------------------------------------------ */
/*  Trending Areas                                                     */
/* ------------------------------------------------------------------ */

export interface TrendingAreaItem {
  districtId: string;
  name: string;
  listings: number;
  inquiries: number;
  views: number;
  priceChangePct: number | null;
  scoreRank: number;
}

export interface TrendingAreasResponse {
  period: number;
  level: string;
  limit: number;
  areas: TrendingAreaItem[];
}

export const analyticsApi = {
  // All /analytics/* endpoints are wrapped by the backend CacheMetaInterceptor.
  // We unwrap the `{ data, cacheMeta }` envelope so callers get the plain DTO.
  getMarketReport: (city: string, period: string, propertyType?: string) => {
    const params = new URLSearchParams({ city, period });
    if (propertyType) params.set('propertyType', propertyType);
    return unwrap<MarketReportResponse>(
      apiClient.get<CacheMetaEnvelope<MarketReportResponse>>(
        `/analytics/market-report?${params}`,
      ),
    );
  },

  getHeatmap: (city: string, period: string) => {
    const params = new URLSearchParams({ city, period });
    return unwrap<HeatmapResponse>(
      apiClient.get<CacheMetaEnvelope<HeatmapResponse>>(`/analytics/heatmap?${params}`),
    );
  },

  getPriceTrend: (district: string, city: string, propertyType: string, periods: string[]) => {
    const params = new URLSearchParams({ district, city, propertyType, periods: periods.join(',') });
    return unwrap<PriceTrendResponse>(
      apiClient.get<CacheMetaEnvelope<PriceTrendResponse>>(
        `/analytics/price-trend?${params}`,
      ),
    );
  },

  getDistrictStats: (city: string, period: string) => {
    const params = new URLSearchParams({ city, period });
    return unwrap<DistrictStatsResponse>(
      apiClient.get<CacheMetaEnvelope<DistrictStatsResponse>>(
        `/analytics/district-stats?${params}`,
      ),
    );
  },

  getNearbyPOIs: (lat: number, lng: number, radius = 2000, limit = 30) =>
    unwrap<NearbyPOIsResponse>(
      apiClient.get<CacheMetaEnvelope<NearbyPOIsResponse>>(
        `/analytics/pois/nearby?lat=${lat}&lng=${lng}&radius=${radius}&limit=${limit}`,
      ),
    ),

  getListingAiAdvice: (listingId: string) =>
    unwrap<ListingAiAdvice>(
      apiClient.post<CacheMetaEnvelope<ListingAiAdvice>>(
        `/analytics/listings/${listingId}/ai-advice`,
      ),
    ),

  getProjectAiAdvice: (projectId: string) =>
    unwrap<ProjectAiAdvice>(
      apiClient.post<CacheMetaEnvelope<ProjectAiAdvice>>(
        `/analytics/projects/${projectId}/ai-advice`,
      ),
    ),

  getMarketSnapshot: (city: string, propertyType?: string) => {
    const params = new URLSearchParams({ city });
    if (propertyType) params.set('propertyType', propertyType);
    return unwrap<MarketSnapshotResponse>(
      apiClient.get<CacheMetaEnvelope<MarketSnapshotResponse>>(
        `/analytics/market-snapshot?${params}`,
      ),
    );
  },

  getPriceMovers: (direction: 'up' | 'down', period = '7d', limit = 5) => {
    const params = new URLSearchParams({ direction, period, limit: String(limit) });
    return unwrap<PriceMoversResponse>(
      apiClient.get<CacheMetaEnvelope<PriceMoversResponse>>(
        `/analytics/price-movers?${params}`,
      ),
    );
  },

  getTrendingAreas: (period = 7, limit = 10) => {
    const params = new URLSearchParams({ period: String(period), limit: String(limit) });
    return unwrap<TrendingAreasResponse>(
      apiClient.get<CacheMetaEnvelope<TrendingAreasResponse>>(
        `/analytics/trending-areas?${params}`,
      ),
    );
  },
};
