// Manual TS types for /best-layouts endpoint (Issue #113)
// Source: backend/app/schemas/parcel.py — BestLayoutsRequest, BestLayoutsResponse et al.
// Update if Pydantic schemas change and codegen is available.

export type TimeWindow = "last_month" | "last_quarter" | "last_year";
export type RoomBucket = "studio" | "1" | "2" | "3" | "4+";
export type AreaBin = "<25" | "25-40" | "40-60" | "60-80" | "80-100" | "100+";
export type Confidence = "high" | "medium" | "low";

export interface BestLayoutsRequest {
  radius_km: number;
  time_window: TimeWindow;
  filter_competitor_obj_ids?: number[] | null;
  exclude_competitor_obj_ids?: number[];
  min_velocity_per_month?: number;
  obj_class_filter?: "economy" | "comfort" | "business" | null;
  target_total_flats?: number | null;
}

export interface TopLayoutRow {
  rank: number;
  room_bucket: string;
  area_bin: string;
  signature: string;
  competitor_obj_ids: number[];
  competitor_count: number;
  total_sold_in_window: number;
  velocity_per_month: number;
  avg_price_per_m2_rub: number | null;
  avg_area_m2: number;
  supply_units_in_radius: number;
  sold_pct_of_supply: number | null; // clamped at 100.0
  is_oversold: boolean; // raw ratio was >100% (incompatible time windows)
}

export interface SupplyOnlyLayoutRow {
  // Issue #2177 шаг 3: структура текущего ПРЕДЛОЖЕНИЯ (без темпа продаж) для
  // комплексов, сматченных по ядру имени, но без данных о сделках. Источник —
  // objective_lots (снапшот остатков в продаже).
  project_name: string;
  room_bucket: string;
  area_bin: string;
  lots_count: number;
  median_price_m2: number | null;
  median_area_m2: number | null;
  source: string; // всегда 'objective_lots'
}

export interface LayoutTzMixRow {
  room_bucket: string;
  pct: number;
  abs_units: number | null;
  avg_target_area_m2: number | null;
}

export interface LayoutTzRecommendation {
  rationale_text: string;
  mix: LayoutTzMixRow[];
  weighted_avg_price_per_m2_rub: number | null;
  based_on_obj_count: number;
  based_on_total_deals: number;
  data_window_start: string;
  data_window_end: string;
  /** Fix SF-09: true если pathological case — все bucket'ы > cap, redistribute невозможен. */
  cap_skipped: boolean;
}

export interface LayoutDataQuality {
  // Issue #2177: objects_* считают комплексы (сгруппированные obj_id), а не сырые
  // obj_id. raw_objects_total — сырое число obj_id до группировки (прозрачность).
  objects_with_velocity_data: number;
  objects_total_in_radius: number;
  raw_objects_total: number;
  // Issue #2177 шаг 2b: сколько комплексов покрыто по ЯДРУ имени (project_name-матч),
  // а не через mapping-obj_id — прозрачность источника атрибуции velocity.
  groups_matched_by_core: number;
  // Issue #2177 шаг 3: сколько комплексов попало в блок «по предложению» (сматчены
  // по ядру, без velocity, но с лотами в продаже). Аддитивно, default 0.
  groups_with_supply_only: number;
  velocity_coverage_pct: number;
  confidence: Confidence;
}

export interface BestLayoutsResponse {
  top_layouts: TopLayoutRow[];
  recommendation_for_tz: LayoutTzRecommendation;
  data_quality: LayoutDataQuality;
  // Issue #2177 шаг 3: fallback-блок «по предложению без темпа продаж». Пустой
  // массив, если у всех сматченных комплексов есть velocity или нет лотов.
  supply_only_layouts: SupplyOnlyLayoutRow[];
}
