-- NSPD scrape industrialization: schema baseline.
--
-- 1. cad_buildings — формальная DDL для таблицы, которая создавалась
--    напрямую в проде через 61_import_nspd_batch.py (10590 зданий ЕКБ
--    на момент 2026-04-30). IF NOT EXISTS — миграция идемпотентна.
-- 2. nspd_scrape_runs — журнал автоматизированных Celery-запусков
--    (по образцу kn_scrape_runs из 50_schema_kn_extensions.sql).
-- 3. nspd_scrape_log — построчный лог стадий (по образцу kn_scrape_log).

CREATE EXTENSION IF NOT EXISTS postgis;

-- ── 1. cad_buildings ─────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS cad_buildings (
    cad_num             TEXT PRIMARY KEY,
    quarter_cad_num     TEXT REFERENCES cad_quarters_geom(cad_number) ON DELETE SET NULL,
    geom                geometry(Geometry, 4326),
    purpose             TEXT,
    building_name       TEXT,
    readable_address    TEXT,
    area                NUMERIC,
    floors              INT,
    year_built          INT,
    year_commisioning   INT,
    cost_value          NUMERIC,
    registration_date   DATE,
    status              TEXT,
    ownership_type      TEXT,
    cultural_heritage   TEXT,
    underground_floors  INT,
    build_record_area   NUMERIC,
    build_record_type   TEXT,
    common_data_status  TEXT,
    obj_type            TEXT,
    raw_props           jsonb,
    fetched_at          timestamptz NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS cad_buildings_geom_gist
    ON cad_buildings USING GIST (geom);
CREATE INDEX IF NOT EXISTS cad_buildings_quarter_idx
    ON cad_buildings(quarter_cad_num);
CREATE INDEX IF NOT EXISTS cad_buildings_purpose_idx
    ON cad_buildings(purpose);

COMMENT ON TABLE cad_buildings IS
    'Здания (НСПД thematicSearchId=1) внутри cad_quarters_geom. '
    'Источник cost_value для cross-check с sale_graph.';

-- ── 2. nspd_scrape_runs ──────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS nspd_scrape_runs (
    run_id            BIGSERIAL PRIMARY KEY,
    started_at        timestamptz NOT NULL DEFAULT NOW(),
    finished_at       timestamptz,
    heartbeat_at      timestamptz,
    region_code       INT NOT NULL,
    pending_count     INT,
    quarters_ok       INT NOT NULL DEFAULT 0,
    quarters_failed   INT NOT NULL DEFAULT 0,
    buildings_ok      INT NOT NULL DEFAULT 0,
    requests_count    INT NOT NULL DEFAULT 0,
    waf_429_count     INT NOT NULL DEFAULT 0,
    status            TEXT NOT NULL DEFAULT 'running',  -- running | done | failed | zombie | skipped
    error             TEXT,
    triggered_by      TEXT NOT NULL DEFAULT 'beat'      -- beat | manual | resume
);

CREATE INDEX IF NOT EXISTS nspd_runs_status_idx
    ON nspd_scrape_runs(status, started_at DESC);
CREATE INDEX IF NOT EXISTS nspd_runs_region_idx
    ON nspd_scrape_runs(region_code, started_at DESC);

COMMENT ON TABLE nspd_scrape_runs IS
    'Журнал NSPD-скрейпов кадастровых кварталов и зданий. Один прогон на регион. '
    'Beat-расписание: 20-е число февраля/мая/августа/ноября (после кв. публикаций rosreestr).';

-- ── 3. nspd_scrape_log ───────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS nspd_scrape_log (
    log_id      BIGSERIAL PRIMARY KEY,
    run_id      BIGINT REFERENCES nspd_scrape_runs(run_id) ON DELETE CASCADE,
    ts          timestamptz NOT NULL DEFAULT NOW(),
    level       TEXT NOT NULL DEFAULT 'info',   -- debug | info | warn | error
    stage       TEXT,                            -- task_received | discover | quarter_fetch | buildings | commit | done | error
    cad_number  TEXT,
    message     TEXT
);

CREATE INDEX IF NOT EXISTS nspd_log_run_idx
    ON nspd_scrape_log(run_id, ts DESC);
CREATE INDEX IF NOT EXISTS nspd_log_level_idx
    ON nspd_scrape_log(level, ts DESC) WHERE level IN ('warn', 'error');

COMMENT ON TABLE nspd_scrape_log IS
    'Построчный лог NSPD-скрейпа: какие cad-кварталы успешны/упали, '
    'WAF-403 ретраи, фазы commit. Используется UI /scrape/nspd для мониторинга.';
