-- v_zk_rosreestr_velocity refresh: + cad_buildings cost_value для cross-check.
--
-- Что добавилось vs 60_v_zk_rosreestr_velocity.sql:
--   1. quarter_cadastre_avg_th_per_m2 — медианная кадастровая стоимость м²
--      строений (≥3 этажей) в том же кадастровом квартале.
--   2. cadastre_vs_market_pct — премиум/дисконт рынка относительно кадастра
--      (положительные значения = рынок дороже кадастра, что норма).
--      Аномалии (>+50% или <-30%) пригодны для warning-badge на UI.
--
-- Логика: cad_buildings.cost_value хранится в ₽ на здание; делим на area
-- чтобы получить ₽/м². Берём только residential (purpose ILIKE
-- '%многокварт%' OR floors >= 3) — низкоэтажки и склады искажают.
-- Нет фильтра по году ввода: даже старый фонд даёт ориентир для зонирования.
--
-- Источник истины cost_value: НСПД thematicSearchId=1 → properties.options.cost_value.

CREATE OR REPLACE VIEW v_zk_rosreestr_velocity AS
WITH zk_pool AS (
    SELECT DISTINCT ON (o.obj_id)
           o.obj_id,
           o.comm_name,
           o.dev_name,
           o.district_name,
           o.flat_count,
           o.cad_quarter,
           o.obj_class
      FROM domrf_kn_objects o
     WHERE o.region_cd = 66
       AND o.cad_quarter IS NOT NULL
       AND o.flat_count IS NOT NULL
       AND o.flat_count > 0
       AND o.site_status = 'Строящиеся'
     ORDER BY o.obj_id, o.snapshot_date DESC
),
quarter_totals AS (
    SELECT cad_quarter, SUM(flat_count)::numeric AS total_flats
      FROM zk_pool
     GROUP BY cad_quarter
),
quarter_deals AS (
    SELECT quarter_cad_number AS cad_quarter,
           COUNT(*)                                            AS deals_12mo,
           AVG(price_per_sqm)                                  AS avg_price_pm,
           PERCENTILE_CONT(0.5) WITHIN GROUP
               (ORDER BY price_per_sqm)                        AS median_price_pm,
           AVG(area)                                           AS avg_area_sqm
      FROM rosreestr_deals
     WHERE region_code = 66
       AND doc_type = 'ДДУ'
       AND realestate_type_code = '002001003000'
       AND area > 10 AND area <= 200
       AND price_per_sqm BETWEEN 30000 AND 1000000
       AND period_start_date >= NOW() - INTERVAL '12 months'
     GROUP BY quarter_cad_number
),
quarter_cadastre AS (
    -- Медианная кадастровая стоимость ₽/м² по жилым строениям квартала.
    -- Фильтры:
    --   * cost_value > 0 и area >= 100 м² (исключаем подсобки)
    --   * floors >= 3 ИЛИ purpose ILIKE '%многокв%' (отсеиваем ИЖС/гаражи)
    --   * ₽/м² 5К..500К (уберает мусор и грубые ошибки росреестра)
    SELECT
        quarter_cad_num                                         AS cad_quarter,
        COUNT(*)                                                AS buildings_n,
        PERCENTILE_CONT(0.5) WITHIN GROUP
            (ORDER BY cost_value / NULLIF(area, 0))             AS median_cost_per_m2
      FROM cad_buildings
     WHERE quarter_cad_num IS NOT NULL
       AND cost_value IS NOT NULL
       AND area IS NOT NULL
       AND area >= 100
       -- floors хранится как TEXT (встречаются '1-2', '2-3') —
       -- считаем только чистые числа ≥3, либо purpose-fallback.
       AND ((floors ~ '^[0-9]+$' AND floors::int >= 3)
            OR purpose ILIKE '%многокв%')
       AND (cost_value / NULLIF(area, 0)) BETWEEN 5000 AND 500000
     GROUP BY quarter_cad_num
)
SELECT
    z.obj_id,
    z.comm_name,
    z.dev_name,
    z.district_name,
    z.obj_class,
    z.flat_count,
    z.cad_quarter,
    qt.total_flats                                              AS quarter_total_flats,
    qd.deals_12mo                                               AS quarter_deals_12mo,
    ROUND(qd.deals_12mo * z.flat_count::numeric / qt.total_flats, 1)
                                                                AS estimated_deals_12mo,
    ROUND(qd.deals_12mo * z.flat_count::numeric / qt.total_flats / 12.0, 2)
                                                                AS estimated_velocity_pm,
    ROUND(qd.median_price_pm / 1000.0, 1)                       AS median_price_th_per_m2,
    ROUND(qd.avg_area_sqm, 1)                                   AS avg_deal_area_sqm,
    -- Кадастровая стоимость и cross-check.
    qc.buildings_n                                              AS cadastre_buildings_n,
    ROUND(qc.median_cost_per_m2 / 1000.0, 1)                    AS cadastre_th_per_m2,
    CASE
        WHEN qc.median_cost_per_m2 IS NOT NULL
             AND qd.median_price_pm IS NOT NULL
             AND qc.median_cost_per_m2 > 0
        THEN ROUND(
            (qd.median_price_pm - qc.median_cost_per_m2)
                / qc.median_cost_per_m2 * 100.0,
            1
        )
        ELSE NULL
    END                                                         AS cadastre_vs_market_pct
  FROM zk_pool z
  JOIN quarter_totals qt ON qt.cad_quarter = z.cad_quarter
  JOIN quarter_deals qd ON qd.cad_quarter = z.cad_quarter
  LEFT JOIN quarter_cadastre qc ON qc.cad_quarter = z.cad_quarter
;

COMMENT ON VIEW v_zk_rosreestr_velocity IS
    'v2: per-ЖК velocity/цена через rosreestr-сделки квартала + кадастровая '
    'стоимость м² из cad_buildings (NSPD). cadastre_vs_market_pct = премиум '
    'рынка над кадастром, аномалии (>+50% / <-30%) — outliers для warning UI.';
