from __future__ import annotations

import json
import subprocess
from pathlib import Path


def manifest_rows(
    *,
    database: str,
    row_count: int = 2,
    rowset_md5: str = "a" * 32,
    elapsed_ms: float = 4.0,
    server_address: str | None = None,
    ssl: bool = False,
):
    return [
        {
            "kind": "identity",
            "database": database,
            "current_user": "postgres",
            "server_version_num": 160014,
            "transaction_read_only": "on",
            "server_address": server_address,
            "ssl": ssl,
        },
        {"kind": "schemas", "items": ["kb_stage", "public"]},
        {"kind": "extensions", "items": [{"name": "plpgsql", "version": "1.0"}]},
        {
            "kind": "application_roles",
            "items": [
                {"name": "kb_apply", "can_login": True, "superuser": False},
                {"name": "kb_gate_owner", "can_login": False, "superuser": False},
                {"name": "kb_review", "can_login": True, "superuser": False},
            ],
        },
        {
            "kind": "role_memberships",
            "items": [{"role": "kb_gate_owner", "member": "kb_apply", "admin_option": False}],
        },
        {
            "kind": "object_ownership",
            "items": [{"object_type": "schema", "schema": "public", "name": "public", "owner": "kb_gate_owner"}],
        },
        {
            "kind": "object_acl",
            "items": [{"object_type": "schema", "name": "public", "grantee": "kb_apply", "privilege_type": "USAGE"}],
        },
        {"kind": "columns", "items": [{"schema": "public", "table": "claims", "name": "id"}]},
        {"kind": "constraints", "items": [{"schema": "public", "table": "claims", "name": "claims_pkey"}]},
        {"kind": "indexes", "items": [{"schema": "public", "table": "claims", "name": "claims_pkey"}]},
        {"kind": "sequences", "items": []},
        {"kind": "views", "items": []},
        {"kind": "functions", "items": []},
        {"kind": "triggers", "items": []},
        {"kind": "types", "items": []},
        {"kind": "policies", "items": []},
        {
            "kind": "table",
            "schema": "public",
            "table": "claims",
            "row_count": row_count,
            "rowset_md5": rowset_md5,
        },
        {"kind": "performance", "query": "count_claims", "elapsed_ms": elapsed_ms, "observed_rows": row_count},
    ]


def write_jsonl(path: Path, rows) -> None:
    path.write_text("\n".join(json.dumps(row, sort_keys=True) for row in rows) + "\n")


def run_verifier(tmp_path: Path, source_rows, target_rows, *, scope: str = "local_restore", connectivity=None):
    source = tmp_path / "source.jsonl"
    target = tmp_path / "target.jsonl"
    output = tmp_path / "result.json"
    write_jsonl(source, source_rows)
    write_jsonl(target, target_rows)
    command = [
        "python3",
        "ops/verify_postgres_parity_manifest.py",
        "--source",
        str(source),
        "--target",
        str(target),
        "--scope",
        scope,
        "--output",
        str(output),
    ]
    if connectivity is not None:
        connectivity_path = tmp_path / "connectivity.json"
        connectivity_path.write_text(json.dumps(connectivity))
        command.extend(["--connectivity-proof", str(connectivity_path)])
    completed = subprocess.run(command, text=True, capture_output=True, check=False)
    return completed, json.loads(output.read_text())


def test_matching_local_manifests_pass(tmp_path: Path) -> None:
    completed, payload = run_verifier(
        tmp_path,
        manifest_rows(database="teleo"),
        manifest_rows(database="teleo_copy"),
    )

    assert completed.returncode == 0, completed.stderr
    assert payload["status"] == "pass"
    assert payload["details"]["source_total_rows"] == 2
    assert (
        payload["details"]["application_role_hashes"]["source"]
        == (payload["details"]["application_role_hashes"]["target"])
    )
    assert len(payload["source_manifest_sha256"]) == 64
    assert len(payload["target_manifest_sha256"]) == 64
    assert payload["private_connectivity"]["status"] == "not_applicable_local_restore"
    assert (tmp_path / "result.json").stat().st_mode & 0o777 == 0o600
    assert '"source_database"' not in completed.stdout
    assert '"output_sha256"' in completed.stdout


def test_row_hash_and_role_mismatches_fail(tmp_path: Path) -> None:
    target = manifest_rows(database="teleo_copy", row_count=1, rowset_md5="b" * 32)
    target[3]["items"] = []
    completed, payload = run_verifier(tmp_path, manifest_rows(database="teleo"), target)

    assert completed.returncode == 1
    assert "table_content_mismatches=1" in payload["problems"]
    assert "application_role_mismatches=3" in payload["problems"]


def test_missing_row_hash_and_extra_roles_or_extensions_fail(tmp_path: Path) -> None:
    target = manifest_rows(database="teleo_copy", rowset_md5="")
    target[2]["items"].append({"name": "unreviewed", "version": "1.0"})
    target[3]["items"].append({"name": "project_owner", "can_login": True, "superuser": True})

    completed, payload = run_verifier(tmp_path, manifest_rows(database="teleo"), target)

    assert completed.returncode == 1
    assert "table_hash_problems=1" in payload["problems"]
    assert "extension_mismatches=1" in payload["problems"]
    assert "application_role_mismatches=1" in payload["problems"]
    assert payload["details"]["target_extra_extensions"] == ["unreviewed"]
    assert payload["details"]["target_extra_application_roles"] == ["project_owner"]


def test_matching_malformed_row_hashes_fail(tmp_path: Path) -> None:
    completed, payload = run_verifier(
        tmp_path,
        manifest_rows(database="teleo", rowset_md5="not-a-hash"),
        manifest_rows(database="teleo_copy", rowset_md5="not-a-hash"),
    )

    assert completed.returncode == 1
    assert "table_hash_problems=2" in payload["problems"]
    assert payload["details"]["table_mismatches"] == []


def test_authorization_ownership_or_acl_drift_fails(tmp_path: Path) -> None:
    target = manifest_rows(database="teleo_copy")
    target[5]["items"][0]["owner"] = "postgres"

    completed, payload = run_verifier(tmp_path, manifest_rows(database="teleo"), target)

    assert completed.returncode == 1
    assert "object_ownership_hash_mismatch" in payload["problems"]


def test_gcp_scope_requires_private_connectivity_receipt(tmp_path: Path) -> None:
    completed, payload = run_verifier(
        tmp_path,
        manifest_rows(database="teleo"),
        manifest_rows(database="teleo_gcp_copy"),
        scope="gcp_staging",
    )

    assert completed.returncode == 1
    assert "gcp_private_connectivity_proof_missing" in payload["problems"]


def test_gcp_scope_accepts_matching_private_connectivity_receipt(tmp_path: Path) -> None:
    completed, payload = run_verifier(
        tmp_path,
        manifest_rows(database="teleo"),
        manifest_rows(database="teleo_gcp_copy", server_address="10.61.0.3/32", ssl=True),
        scope="gcp_staging",
        connectivity={
            "status": "pass",
            "private_connectivity": True,
            "public_ip_disabled": True,
            "source_compute": "teleo-staging-1",
            "target_database": "teleo_gcp_copy",
            "server_address": "10.61.0.3",
            "ssl": True,
            "sslmode": "verify-full",
            "ssl_server_name": "teleo-pgvector-standby.private.teleo.internal",
            "ssl_root_cert_sha256": "a" * 64,
            "server_identity_verified": True,
        },
    )

    assert completed.returncode == 0, completed.stderr
    assert payload["status"] == "pass"
    assert payload["private_connectivity"]["proof"]["source_compute"] == "teleo-staging-1"
    assert len(payload["connectivity_proof_sha256"]) == 64


def test_gcp_scope_rejects_receipt_for_a_different_server(tmp_path: Path) -> None:
    completed, payload = run_verifier(
        tmp_path,
        manifest_rows(database="teleo"),
        manifest_rows(database="teleo_gcp_copy", server_address="10.61.0.3", ssl=True),
        scope="gcp_staging",
        connectivity={
            "status": "pass",
            "private_connectivity": True,
            "public_ip_disabled": True,
            "source_compute": "teleo-staging-1",
            "target_database": "teleo_gcp_copy",
            "server_address": "10.61.0.4",
            "ssl": True,
            "sslmode": "verify-full",
            "ssl_server_name": "teleo-pgvector-standby.private.teleo.internal",
            "ssl_root_cert_sha256": "a" * 64,
            "server_identity_verified": True,
        },
    )

    assert completed.returncode == 1
    assert "gcp_connectivity_server_address_mismatch" in payload["problems"]


def test_gcp_scope_rejects_public_or_non_tls_target_manifest(tmp_path: Path) -> None:
    completed, payload = run_verifier(
        tmp_path,
        manifest_rows(database="teleo"),
        manifest_rows(database="teleo_gcp_copy", server_address="34.1.2.3", ssl=False),
        scope="gcp_staging",
        connectivity={
            "status": "pass",
            "private_connectivity": True,
            "public_ip_disabled": True,
            "source_compute": "teleo-staging-1",
            "target_database": "teleo_gcp_copy",
            "server_address": "34.1.2.3",
            "ssl": False,
            "sslmode": "verify-full",
            "ssl_server_name": "teleo-pgvector-standby.private.teleo.internal",
            "ssl_root_cert_sha256": "a" * 64,
            "server_identity_verified": True,
        },
    )

    assert completed.returncode == 1
    assert "gcp_target_manifest_server_address_not_rfc1918" in payload["problems"]
    assert "gcp_target_manifest_tls_not_proven" in payload["problems"]
    assert "gcp_connectivity_tls_not_proven" in payload["problems"]
