-- 094_cadastral_unify.sql
-- Purpose: Унификация имени кадастрового столбца kadastr_num → cadastral_number
--          во всех таблицах tradein-БД.
--
-- Контекст (Issue #732):
--   deals.kadastr_num          → RENAME TO cadastral_number
--   house_metadata.kadastr_num → RENAME TO cadastral_number
--   listings.kadastr_num       → DROP (данные 0%; listings.cadastral_number уже существует
--                                       — добавлен в 019_listings_alter_cian.sql)
--   listings_search_mv         → DROP + RECREATE (ссылался на l.kadastr_num → l.cadastral_number)
--   v_data_quality             → DROP + RECREATE (ссылался на kadastr_num в active_listings CTE)
--
-- Idempotency:
--   * RENAME: обёрнуты в DO $$ ... $$ блок с проверкой information_schema.columns.
--     Повторный запуск: столбец уже переименован → IF NOT EXISTS → skip.
--   * DROP/DROP IF EXISTS: безопасны при повторном запуске.
--   * RECREATE: CREATE OR REPLACE VIEW / CREATE MATERIALIZED VIEW после DROP IF EXISTS.
--
-- ВНИМАНИЕ: DESTRUCTIVE DDL. Применять только после проверки данных на проде.
--   AUTO-APPLIES ON DEPLOY — merge-gate требуется (post-demo).
--
-- Dependencies:
--   002_core_tables.sql (deals, listings, house_metadata)
--   019_listings_alter_cian.sql (listings.cadastral_number already exists)
--   046_views.sql (v_data_quality, v_price_divergence)
--   050_search_optimization.sql (listings_search_mv)

BEGIN;

-- =============================================================================
-- 1. Drop dependent objects (view + materialized view)
--    Нужно до RENAME/DROP колонок, иначе PG откажет (зависимые объекты).
-- =============================================================================

DROP MATERIALIZED VIEW IF EXISTS listings_search_mv;
DROP VIEW IF EXISTS v_data_quality;

-- =============================================================================
-- 2. Rename deals.kadastr_num → cadastral_number (idempotent)
-- =============================================================================

DO $$
BEGIN
    IF EXISTS (
        SELECT 1 FROM information_schema.columns
         WHERE table_schema = 'public'
           AND table_name   = 'deals'
           AND column_name  = 'kadastr_num'
    ) THEN
        ALTER TABLE deals RENAME COLUMN kadastr_num TO cadastral_number;
    END IF;
END
$$;

-- =============================================================================
-- 3. Rename house_metadata.kadastr_num → cadastral_number (idempotent)
--    house_metadata.kadastr_num имеет UNIQUE constraint — переименование сохраняет его.
-- =============================================================================

DO $$
BEGIN
    IF EXISTS (
        SELECT 1 FROM information_schema.columns
         WHERE table_schema = 'public'
           AND table_name   = 'house_metadata'
           AND column_name  = 'kadastr_num'
    ) THEN
        ALTER TABLE house_metadata RENAME COLUMN kadastr_num TO cadastral_number;
    END IF;
END
$$;

-- =============================================================================
-- 4. Удаляем listings.kadastr_num + его индекс
--    listings.cadastral_number (кадастровый номер квартиры, из Cian) уже существует
--    с 019_listings_alter_cian.sql — данные в kadastr_num 0%, копировать не нужно.
-- =============================================================================

DROP INDEX IF EXISTS listings_kadastr_idx;

DO $$
BEGIN
    IF EXISTS (
        SELECT 1 FROM information_schema.columns
         WHERE table_schema = 'public'
           AND table_name   = 'listings'
           AND column_name  = 'kadastr_num'
    ) THEN
        ALTER TABLE listings DROP COLUMN kadastr_num;
    END IF;
END
$$;

-- =============================================================================
-- 5. Recreate v_data_quality
--    Изменение: kadastr_num → cadastral_number (listings.cadastral_number из 019).
--    CREATE OR REPLACE VIEW — идемпотентно.
-- =============================================================================

CREATE OR REPLACE VIEW v_data_quality AS
WITH active_listings AS (
    SELECT * FROM listings WHERE is_active = true
)
SELECT
    (SELECT count(*) FROM houses)                                                  AS houses_total,
    (SELECT count(*) FROM houses h
       WHERE EXISTS (SELECT 1 FROM house_sources hs WHERE hs.house_id = h.id))      AS houses_with_source,
    (SELECT count(*) FROM houses h
       WHERE EXISTS (SELECT 1 FROM house_sources hs
                      WHERE hs.house_id = h.id AND hs.ext_source = 'avito'))        AS houses_with_avito,
    (SELECT count(*) FROM houses h
       WHERE EXISTS (SELECT 1 FROM house_sources hs
                      WHERE hs.house_id = h.id AND hs.ext_source LIKE 'cian%'))     AS houses_with_cian,
    (SELECT count(*) FROM houses h
       WHERE EXISTS (SELECT 1 FROM house_sources hs
                      WHERE hs.house_id = h.id AND hs.ext_source = 'yandex'))       AS houses_with_yandex,
    (SELECT count(*) FROM (
        SELECT house_id FROM house_sources GROUP BY house_id HAVING count(*) >= 2
    ) sub)                                                                          AS houses_2plus_sources,
    (SELECT count(*) FROM (
        SELECT house_id FROM house_sources GROUP BY house_id HAVING count(*) >= 3
    ) sub)                                                                          AS houses_3plus_sources,
    (SELECT count(*) FROM active_listings)                                         AS listings_active,
    (SELECT count(*) FROM (
        SELECT listing_id FROM listing_sources
         WHERE listing_id IN (SELECT id FROM active_listings)
         GROUP BY listing_id HAVING count(*) >= 2
    ) sub)                                                                          AS listings_dedup_2sources,
    (SELECT count(*) FROM active_listings WHERE lat IS NOT NULL) * 100.0
        / NULLIF((SELECT count(*) FROM active_listings), 0)                         AS pct_geocoded,
    (SELECT count(*) FROM active_listings WHERE cadastral_number IS NOT NULL) * 100.0
        / NULLIF((SELECT count(*) FROM active_listings), 0)                         AS pct_cadastr,
    (SELECT count(*) FROM active_listings WHERE description IS NOT NULL) * 100.0
        / NULLIF((SELECT count(*) FROM active_listings), 0)                         AS pct_description,
    (SELECT count(*) FROM active_listings l
       JOIN houses h ON h.id = l.house_id_fk
       WHERE h.year_built IS NOT NULL) * 100.0
        / NULLIF((SELECT count(*) FROM active_listings), 0)                         AS pct_year_built,
    NOW() - (SELECT max(scraped_at) FROM listings WHERE source = 'avito')           AS avito_last_scrape_ago,
    NOW() - (SELECT max(scraped_at) FROM listings WHERE source = 'cian')            AS cian_last_scrape_ago,
    NOW() - (SELECT max(scraped_at) FROM listings WHERE source = 'yandex')          AS yandex_last_scrape_ago,
    (SELECT count(*) FROM v_price_divergence)                                       AS price_disagreements_count,
    (SELECT count(*) FROM listings WHERE is_outlier = true)                         AS outliers_flagged;

COMMENT ON VIEW v_data_quality IS
  'KPI snapshot. Refreshed on-demand by /api/v1/admin/data-quality endpoint (Master Plan sec 8.1).';

-- =============================================================================
-- 6. Recreate listings_search_mv
--    Изменение: l.kadastr_num → l.cadastral_number (apartment-level из 019_listings_alter_cian).
--    Все 6 индексов воссоздаются (см. 050_search_optimization.sql).
-- =============================================================================

CREATE MATERIALIZED VIEW listings_search_mv AS
SELECT
    l.id                AS listing_id,
    l.source,
    l.source_url,
    l.address,
    l.geom,
    l.lat,
    l.lon              AS lng,
    l.rooms,
    l.area_m2          AS total_area,
    l.floor,
    l.total_floors,
    l.price_rub,
    l.price_per_m2,
    l.cadastral_number,
    l.is_active,
    l.scraped_at,
    -- House denorm
    h.id               AS house_id,
    h.year_built,
    h.house_class,
    h.developer_name,
    h.rating           AS house_rating,
    h.reviews_count    AS house_ratings_count,
    -- Cross-source aggregates
    (SELECT count(*)               FROM listing_sources ls WHERE ls.listing_id = l.id) AS source_count,
    (SELECT array_agg(DISTINCT ext_source) FROM listing_sources ls WHERE ls.listing_id = l.id) AS sources,
    (SELECT bool_or(ext_source = 'avito')         FROM listing_sources ls WHERE ls.listing_id = l.id) AS has_avito,
    (SELECT bool_or(ext_source = 'cian')          FROM listing_sources ls WHERE ls.listing_id = l.id) AS has_cian,
    (SELECT bool_or(ext_source = 'yandex_realty') FROM listing_sources ls WHERE ls.listing_id = l.id) AS has_yandex,
    -- Price percentile within house
    (SELECT percentile_cont(0.5) WITHIN GROUP (ORDER BY ll.price_per_m2)
       FROM listings ll
      WHERE ll.house_id_fk = l.house_id_fk AND ll.is_active = true) AS house_median_ppm2,
    -- DEFAULT: district / distance_to_metro_m / last_price_change / photos_count
    -- not present in current schema — placeholders.
    NULL::text                          AS district,
    NULL::int                           AS distance_to_metro_m,
    NULL::timestamptz                   AS last_price_change,
    NULL::int                           AS photos_count,
    -- Trigram-ready columns
    l.address                           AS address_trgm,
    -- Aggregated tsv (description + address + developer_name)
    to_tsvector('russian',
        coalesce(l.description, '') || ' ' ||
        coalesce(l.address, '')     || ' ' ||
        coalesce(h.developer_name, '')
    ) AS tsv
FROM listings l
LEFT JOIN houses h ON h.id = l.house_id_fk
WHERE l.is_active = true
  AND COALESCE(l.canonical, true) = true;

-- 6 matview indexes (воссоздаются без IF NOT EXISTS — MV была только что создана)
CREATE UNIQUE INDEX listings_search_mv_id_idx
  ON listings_search_mv (listing_id);

CREATE INDEX listings_search_mv_geom_idx
  ON listings_search_mv USING GIST (geom);

CREATE INDEX listings_search_mv_filters_idx
  ON listings_search_mv (rooms, price_rub, total_area, scraped_at DESC);

CREATE INDEX listings_search_mv_address_trgm_idx
  ON listings_search_mv USING GIN (address_trgm gin_trgm_ops);

CREATE INDEX listings_search_mv_tsv_idx
  ON listings_search_mv USING GIN (tsv);

CREATE INDEX listings_search_mv_sources_idx
  ON listings_search_mv (has_avito, has_cian, has_yandex);

-- Populate materialized view (первый запуск — CONCURRENTLY недоступен на новой MV).
REFRESH MATERIALIZED VIEW listings_search_mv;

COMMIT;
