"""Static guards for migration 189 (account_estimate_usage.used >= 0).

Прод применяет data/sql построчно строго (ON_ERROR_STOP). Полный DB-прогон
требует живой БД; здесь фиксируем структурные инварианты, которые ГАРАНТИРУЮТ
идемпотентность и что миграция реально закрывает negative-used класс дефекта
(прежний SQL-runbook хак `used = used - N`, см. migration 185 которая сбросила
это только для user2 — praktika осталась с used=-3 за 2026-06).
"""

from __future__ import annotations

import re
from pathlib import Path

_SQL_DIR = Path(__file__).resolve().parents[1] / "data" / "sql"
_MIGRATION_189 = _SQL_DIR / "189_account_estimate_usage_nonnegative.sql"


def _sql() -> str:
    return _MIGRATION_189.read_text(encoding="utf-8")


def _executable_sql() -> str:
    """SQL без построчных `--`-комментариев — только исполняемый код."""
    lines = []
    for raw in _sql().splitlines():
        code = raw.split("--", 1)[0]
        if code.strip():
            lines.append(code)
    return "\n".join(lines)


def _flat(text: str) -> str:
    return re.sub(r"\s+", " ", text).strip().lower()


def test_migration_189_exists() -> None:
    assert _MIGRATION_189.exists(), f"missing migration: {_MIGRATION_189}"


def test_migration_189_is_transactional() -> None:
    sql = _sql()
    assert "BEGIN;" in sql
    assert "COMMIT;" in sql


def test_migration_189_resets_all_negative_used_not_scoped_to_user2() -> None:
    """UPDATE ... WHERE used < 0 без username-фильтра — закрывает praktika и любой
    другой пропущенный аккаунт, не только user2 (как было в migration 185)."""
    flat = _flat(_executable_sql())
    assert "update account_estimate_usage" in flat
    assert "set used = 0" in flat
    assert "where used < 0" in flat
    # НЕ должен быть заскоуплен на конкретного пользователя.
    assert "username = 'user2'" not in flat


def test_migration_189_adds_nonnegative_check_constraint() -> None:
    """CHECK (used >= 0) — схема защищает от будущих ручных UPDATE в минус."""
    flat = _flat(_executable_sql())
    assert "add constraint account_estimate_usage_used_nonnegative" in flat
    assert "check (used >= 0)" in flat


def test_migration_189_constraint_add_is_idempotent() -> None:
    """ADD CONSTRAINT обёрнут в идемпотентную проверку по pg_constraint.conname —
    Postgres не поддерживает `ADD CONSTRAINT IF NOT EXISTS` напрямую для CHECK."""
    flat = _flat(_executable_sql())
    assert "pg_constraint" in flat
    assert "conname = 'account_estimate_usage_used_nonnegative'" in flat


def test_migration_189_no_psycopg_trap() -> None:
    """Никаких :param::type — psycopg v3 требует CAST(... AS type) (не применимо
    в чистом .sql без bind params, но проверяем на регресс copy-paste)."""
    assert not re.search(r":\w+::", _sql())
