"""Schema-shape assertions on alembic head (T-MIG-009; judgments #32/#33).

Dropped columns are GONE, carried columns are PRESENT, no sets/tasks
tables exist, and the users -> parties link landed (ADR #002 #5)."""

import pytest
from sqlalchemy import inspect

FORBIDDEN_COLUMNS = {
    "transferred_at", "transferred_by", "transfer_batch_id", "converted_user",
    "converted_duration_seconds", "rate_proportion", "base_rate_usd",
    "default_hourly_rate_usd", "hourly_rate_usd", "must_change_password",
}


@pytest.fixture(scope="module")
def inspector(mig_engine):
    return inspect(mig_engine)


def test_forbidden_columns_are_gone_everywhere(inspector):
    for table in inspector.get_table_names(schema="public"):
        columns = {c["name"] for c in inspector.get_columns(table, schema="public")}
        assert not (columns & FORBIDDEN_COLUMNS), (
            f"{table} still carries dropped columns: {columns & FORBIDDEN_COLUMNS}"
        )


def test_carried_columns_are_present(inspector):
    te = {c["name"] for c in inspector.get_columns("time_entries")}
    assert {"source_rate", "source_amount", "raw_operator", "raw_client",
            "raw_project", "source_timezone", "cost_amount", "cost_currency",
            "billout_amount", "billout_currency", "invoice_line_id"} <= te
    inv = {c["name"] for c in inspector.get_columns("invoices")}
    assert {"manual_total", "currency", "from_party_id", "to_party_id",
            "invoice_date", "sent_at", "paid_at", "created_by", "notes"} <= inv
    lines = {c["name"] for c in inspector.get_columns("invoice_lines")}
    assert {"kind", "attached_at", "attached_by", "snapshot_client_name",
            "snapshot_project_name"} <= lines


def test_no_sets_or_tasks_tables_and_no_task_id(inspector):
    tables = set(inspector.get_table_names(schema="public"))
    assert not ({"sets", "tasks", "assignments"} & tables)  # judgment #32
    te = {c["name"] for c in inspector.get_columns("time_entries")}
    assert "task_id" not in te


def test_expected_r1_tables_exist(inspector):
    tables = set(inspector.get_table_names(schema="public"))
    assert {
        "parties", "tenants", "users", "engagements", "compensation_terms",
        "rate_overrides", "projects", "import_batches", "time_entries",
        "invoices", "invoice_lines", "cc_expense_batches", "cc_expense_lines",
        "cc_highlight_keywords", "cc_auto_rules", "comments", "audit_log",
        "migration_runs",
    } <= tables


def test_users_person_party_fk_and_unique(inspector):
    fks = inspector.get_foreign_keys("users")
    assert any(
        fk["referred_table"] == "parties"
        and fk["constrained_columns"] == ["person_party_id"]
        for fk in fks
    ), "users.person_party_id FK -> parties missing (deferred from M1)"
    uniques = {tuple(u["column_names"]) for u in inspector.get_unique_constraints("users")}
    assert ("person_party_id",) in uniques


def test_project_uniqueness_is_tenant_scoped(mig_engine):
    # judgment #33: (tenant_id, client_party_id, lower(name))
    from sqlalchemy import text

    with mig_engine.connect() as conn:
        definition = conn.execute(text(
            "SELECT indexdef FROM pg_indexes WHERE tablename = 'projects'"
            " AND indexname = 'uq_projects_tenant_client_lower_name'"
        )).scalar()
    assert definition and "UNIQUE" in definition
    for fragment in ("tenant_id", "client_party_id", "lower(name"):
        assert fragment in definition
