-- Унификация naming: region_cd/region_code → region_id, dev_id → developer_id,
-- dev_name → developer_name.
--
-- ПОДХОД: GENERATED ALWAYS AS (...) STORED — добавляем синонимные колонки
-- которые автоматически синхронизируются с источником. НЕ ALTER RENAME COLUMN
-- (последний сразу сломает работающий backend, который ссылается на старые
-- имена в SQL text() literals в 10 файлах).
--
-- Backend продолжает работать со старыми именами. Новый код может
-- использовать унифицированные. Постепенно мигрировать backend → потом DROP
-- старых колонок отдельной миграцией.
--
-- Storage cost: int 4B × N rows. Для rosreestr_deals (~7M rows) = ~28 MB.
-- Суммарно по всем таблицам ~50 MB. Приемлемо.
--
-- Применено в проде через mcp postgres 2026-05-10.
-- Идемпотентно через ADD COLUMN IF NOT EXISTS.

-- ── Plus task 2/3 (выполнены отдельным запросом, документирую здесь) ────────
-- UPDATE complexes SET obj_class и district_name из objective_lots для 350
-- сматченных через cs.source='objective'. obj_class заполнен = 350,
-- district_name = 1525 (приоритет — Objective).

-- ── region_cd → region_id (5 таблиц) ────────────────────────────────────────
ALTER TABLE domrf_kn_objects        ADD COLUMN IF NOT EXISTS region_id INT GENERATED ALWAYS AS (region_cd) STORED;
ALTER TABLE domrf_kn_flats          ADD COLUMN IF NOT EXISTS region_id INT GENERATED ALWAYS AS (region_cd) STORED;
ALTER TABLE domrf_project_finance   ADD COLUMN IF NOT EXISTS region_id INT GENERATED ALWAYS AS (region_cd) STORED;
ALTER TABLE domrf_sold_ready_breakdown ADD COLUMN IF NOT EXISTS region_id INT GENERATED ALWAYS AS (region_cd) STORED;
ALTER TABLE rosreestr_rent_deals    ADD COLUMN IF NOT EXISTS region_id INT GENERATED ALWAYS AS (region_cd) STORED;

-- ── region_code → region_id (3 таблицы; rosreestr_deals = partitioned, → 9 партиций) ──
ALTER TABLE domrf_realization       ADD COLUMN IF NOT EXISTS region_id INT GENERATED ALWAYS AS (region_code) STORED;
ALTER TABLE nspd_scrape_runs        ADD COLUMN IF NOT EXISTS region_id INT GENERATED ALWAYS AS (region_code) STORED;
ALTER TABLE rosreestr_deals         ADD COLUMN IF NOT EXISTS region_id INT GENERATED ALWAYS AS (region_code) STORED;

-- ── dev_id → developer_id (3 таблицы) ───────────────────────────────────────
ALTER TABLE domrf_kn_objects        ADD COLUMN IF NOT EXISTS developer_id   TEXT GENERATED ALWAYS AS (dev_id)   STORED;
ALTER TABLE domrf_dev_growth        ADD COLUMN IF NOT EXISTS developer_id   TEXT GENERATED ALWAYS AS (dev_id)   STORED;
ALTER TABLE sv_dev_sales            ADD COLUMN IF NOT EXISTS developer_id   TEXT GENERATED ALWAYS AS (dev_id)   STORED;

-- ── dev_name → developer_name (2 таблицы) ───────────────────────────────────
ALTER TABLE domrf_kn_objects        ADD COLUMN IF NOT EXISTS developer_name TEXT GENERATED ALWAYS AS (dev_name) STORED;
ALTER TABLE domrf_dev_growth        ADD COLUMN IF NOT EXISTS developer_name TEXT GENERATED ALWAYS AS (dev_name) STORED;

-- ── COMMENT-указатель миграции ──────────────────────────────────────────────
COMMENT ON COLUMN domrf_kn_objects.region_cd IS
    'DEPRECATED: используй region_id (синоним через GENERATED). '
    'Удалить после миграции backend SQL queries.';
COMMENT ON COLUMN domrf_kn_objects.dev_id IS
    'DEPRECATED: используй developer_id (синоним через GENERATED).';
COMMENT ON COLUMN domrf_kn_objects.dev_name IS
    'DEPRECATED: используй developer_name (синоним через GENERATED).';
COMMENT ON COLUMN rosreestr_deals.region_code IS
    'DEPRECATED: используй region_id (синоним через GENERATED).';

-- ── 4. complexes update: obj_class + district из Objective ──────────────────
WITH objective_per_complex AS (
    SELECT DISTINCT ON (cs.complex_id) cs.complex_id,
           ol.class AS obj_class,
           ol.district AS district_name
      FROM complex_sources cs
      JOIN objective_lots ol ON ol.project_name = cs.source_id
     WHERE cs.source = 'objective'
     ORDER BY cs.complex_id, ol.snapshot_date DESC NULLS LAST
)
UPDATE complexes c
   SET obj_class = COALESCE(opc.obj_class, c.obj_class),
       district_name = COALESCE(opc.district_name, c.district_name),
       updated_at = NOW()
  FROM objective_per_complex opc
 WHERE opc.complex_id = c.id;

-- ── 5. Fuzzy auto-merge orphan complexes (high-confidence ≥0.85) ────────────
-- См. полный SQL-блок в applied миграции через mcp postgres.
-- Эффект: 14 high-confidence orphan Objective complexes слились с domrf_kn
-- (например 'Чемпион Парк' / 'Discovery Residence' / 'АЛЛЕГРО'). После merge:
-- complexes 1752 → 1740, in_both_sources_now 114 → 124.

-- ── 6. v_complex_match_review для остальных 82 кандидатов ───────────────────
CREATE EXTENSION IF NOT EXISTS pg_trgm;

CREATE OR REPLACE VIEW v_complex_match_review AS
WITH orphan_complexes AS (
    SELECT c.id AS orphan_id, c.canonical_name AS orphan_name,
           c.developer_name AS orphan_dev, c.district_name AS orphan_district,
           c.obj_class AS orphan_class
      FROM complexes c WHERE c.primary_source = 'objective'
),
kn_complexes AS (
    SELECT c.id AS kn_id, c.canonical_name AS kn_name,
           c.developer_name AS kn_dev, c.district_name AS kn_district
      FROM complexes c WHERE c.primary_source = 'domrf_kn'
),
candidates AS (
    SELECT oc.*, kc.kn_id, kc.kn_name, kc.kn_dev, kc.kn_district,
           similarity(oc.orphan_name, kc.kn_name) AS name_sim,
           CASE WHEN oc.orphan_dev IS NOT NULL AND kc.kn_dev IS NOT NULL
                THEN similarity(oc.orphan_dev, kc.kn_dev) ELSE 0 END AS dev_sim,
           CASE WHEN oc.orphan_district = kc.kn_district THEN 1.0 ELSE 0 END AS district_match
      FROM orphan_complexes oc CROSS JOIN kn_complexes kc
     WHERE similarity(oc.orphan_name, kc.kn_name) >= 0.4
),
ranked AS (
    SELECT *, (name_sim * 0.7 + dev_sim * 0.2 + district_match * 0.1) AS combined_score,
           ROW_NUMBER() OVER (PARTITION BY orphan_id ORDER BY (name_sim * 0.7 + dev_sim * 0.2 + district_match * 0.1) DESC) AS rk
      FROM candidates
)
SELECT orphan_id, orphan_name, orphan_dev, orphan_class, orphan_district,
       kn_id, kn_name, kn_dev, kn_district,
       ROUND(name_sim::numeric, 3) AS name_sim,
       ROUND(dev_sim::numeric, 3) AS dev_sim,
       ROUND(combined_score::numeric, 3) AS score,
       CASE WHEN combined_score >= 0.7 THEN 'likely'
            WHEN combined_score >= 0.5 THEN 'maybe'
            ELSE 'unlikely' END AS confidence
  FROM ranked WHERE rk = 1 AND combined_score >= 0.5
 ORDER BY combined_score DESC;

COMMENT ON VIEW v_complex_match_review IS
    'Кандидаты на merge orphan Objective complexes с domrf_kn. Top-1 candidate '
    'per orphan_id с similarity >= 0.5. Для review через admin UI: '
    'если confidence=likely (≥0.7) — почти наверняка дубль, maybe (≥0.5) — '
    'посмотреть глазами. Auto-merge для confidence>=0.85 уже выполнен.';
