"""Apply db/migrations/20260404_norms_governed_aspect.sql to Normbase Postgres once.

Usage (from repo root):
  python normbase/scripts/apply_migration_20260404_norms_governed_aspect.py

Uses NORMBASE_DATABASE_URL or DATABASE_URL (.env loaded if present).
"""
from __future__ import annotations

import asyncio
import os
import re
import sys
from pathlib import Path

try:
    import asyncpg
except ImportError as e:
    raise SystemExit("asyncpg is required. Install project dependencies first.") from e


def _dsn() -> str:
    try:
        from dotenv import load_dotenv

        load_dotenv()
    except ImportError:
        pass
    raw = (os.getenv("NORMBASE_DATABASE_URL") or os.getenv("DATABASE_URL") or "").strip()
    if not raw:
        raise SystemExit("Set NORMBASE_DATABASE_URL or DATABASE_URL.")
    return re.sub(r"^postgresql\+asyncpg", "postgresql", raw, flags=re.I)


# Keep in sync with normbase/db/migrations/20260404_norms_governed_aspect.sql
_STATEMENTS = [
    "ALTER TABLE norms ADD COLUMN IF NOT EXISTS governed_aspect VARCHAR(50)",
    "ALTER TABLE norms DROP CONSTRAINT IF EXISTS ck_governed_aspect",
    """ALTER TABLE norms ADD CONSTRAINT ck_governed_aspect CHECK (
    governed_aspect IS NULL
    OR governed_aspect IN (
        'perceptual',
        'cognitive',
        'evaluative',
        'behavioral',
        'denotative'
    )
)""",
    "CREATE INDEX IF NOT EXISTS idx_norms_governed_aspect ON norms(governed_aspect)",
]


async def _run() -> None:
    conn = await asyncpg.connect(_dsn())
    try:
        for i, sql in enumerate(_STATEMENTS, 1):
            await conn.execute(sql)
            print(f"  [{i}/{len(_STATEMENTS)}] ok")
        print("Migration 20260404_norms_governed_aspect applied successfully.")
    finally:
        await conn.close()


def main() -> None:
    repo_root = Path(__file__).resolve().parents[2]
    os.chdir(repo_root)
    asyncio.run(_run())


if __name__ == "__main__":
    try:
        main()
    except Exception as exc:
        print(f"Migration failed: {exc}", file=sys.stderr)
        sys.exit(1)
