"""End-to-end tests for the M3-M0 governance vertical slice."""
from __future__ import annotations

import os

os.environ.setdefault("AGENTPAAS_DATABASE_URL", "sqlite:///:memory:")
os.environ.setdefault("AGENTPAAS_TESTING", "1")

import pytest

from agentpaas.db.models import Database, now_utc
from agentpaas.governance import service
from agentpaas.governance.agents import execute_governance_agent


@pytest.fixture
def db():
    value = Database("sqlite:///:memory:")
    value.execute(
        "INSERT INTO tenants (id,name,plan,status,created_at) VALUES (?,?,?,?,?)",
        ("tenant-a", "Tenant A", "free", "active", now_utc()),
    )
    value.execute(
        "INSERT INTO tenants (id,name,plan,status,created_at) VALUES (?,?,?,?,?)",
        ("tenant-b", "Tenant B", "free", "active", now_utc()),
    )
    value.commit()
    return value


def test_reference_slice_is_complete_valid_and_idempotent(db):
    first = service.seed_tenant_isolation(db, "tenant-a")
    second = service.seed_tenant_isolation(db, "tenant-a")

    assert first["project"]["id"] == second["project"]["id"]
    assert second["validation"]["valid"] is True
    assert second["validation"]["findings"] == []
    assert second["overview"]["layers"]["M3"] == 8
    assert second["overview"]["layers"]["M0"] == 3
    assert second["overview"]["totals"]["pending_reviews"] == 0


def test_impact_crosses_business_software_and_governance_profiles(db):
    seeded = service.seed_tenant_isolation(db, "tenant-a")
    project_id = seeded["project"]["id"]
    elements = service.list_elements(db, "tenant-a", project_id, query="TenantIdColumn")["items"]
    column = next(item for item in elements if item["name"] == "TenantIdColumn")

    result = service.impact(db, "tenant-a", column["id"], max_depth=5)
    names = {item["name"] for item in result["nodes"]}
    assert {"Tenant", "IAMDataOwner", "TenantIsolationPolicy", "TenantIdCompleteness"} <= names
    assert any(edge["predicate"] == "REPRESENTS" for edge in result["edges"])


def test_tenant_scope_blocks_cross_tenant_reads(db):
    seeded = service.seed_tenant_isolation(db, "tenant-a")
    project_id = seeded["project"]["id"]
    with pytest.raises(service.GovernanceError) as exc:
        service.overview(db, "tenant-b", project_id)
    assert exc.value.status == 404


def test_ddl_agent_persists_facts_candidates_evidence_and_trace(db):
    project = service.create_project(db, "tenant-a", {
        "name": "DDL ingest", "namespace": "https://example.test/ddl",
    })
    ddl = """
    CREATE TABLE dcp_customer (
      id BIGINT PRIMARY KEY,
      mobile VARCHAR(32) NOT NULL,
      created_at TIMESTAMP
    );
    """
    response = execute_governance_agent(db, "tenant-a", project["id"], {
        "source_type": "ddl",
        "source_name": "customer.sql",
        "environment": "production",
        "content": ddl,
    })

    assert response["status"] == "completed"
    assert response["persisted"]["elements"] == 9
    assert response["persisted"]["assertions"] == 11
    assert response["persisted"]["issues"] == 2
    assert {entry["term_name"] for entry in response["trace"]} >= {
        "governance-source-normalizer", "asset-discovery-agent",
        "business-semantics-agent", "governance-controls-agent",
        "governance-synthesis-agent",
    }

    pending = service.list_assertions(
        db, "tenant-a", project["id"], review_status="pending"
    )
    assert len(pending) == 1
    assert pending[0]["predicate"] == "REPRESENTS"
    assert pending[0]["assertion_type"] == "inferred"
    assert pending[0]["evidence_ids"]

    reviewed = service.review_assertion(
        db, "tenant-a", pending[0]["id"], "accepted", "data-steward", "术语已确认"
    )
    assert reviewed["review_status"] == "accepted"
    assert reviewed["reviewer"] == "data-steward"

    runs = db.fetchall(
        "SELECT status,trace_json FROM governance_agent_runs WHERE tenant_id=?",
        ("tenant-a",),
    )
    assert len(runs) == 1 and runs[0]["status"] == "completed"


def test_validation_detects_untyped_published_m0_fact(db):
    project = service.create_project(db, "tenant-a", {
        "name": "Validation", "namespace": "https://example.test/validation",
    })
    fact = service.upsert_element(db, "tenant-a", project["id"], {
        "layer": "M0", "profile": "software", "kind": "PhysicalTable",
        "name": "prod.orphan", "status": "published",
    })
    result = service.validate_project(db, "tenant-a", project["id"], persist=True)
    assert result["valid"] is False
    assert any(item["code"] == "M0_UNKNOWN_TYPE" and item["target_id"] == fact["id"]
               for item in result["findings"])
