"""
Tests for multi-tenancy: tenant management and isolation.

Coverage:
  - POST /v1/admin/tenants       — create tenant (superadmin only)
  - GET  /v1/admin/tenants       — list tenants (superadmin only)
  - DELETE /v1/admin/tenants/{id} — deactivate tenant (superadmin only)
  - Regular key cannot access admin routes
  - Keys are scoped to their own tenant (data isolation)
  - Audit events are isolated per tenant
"""

import uuid

import pytest
from fastapi.testclient import TestClient

from autopil.api.app import create_app


def _eval_payload(**overrides):
    base = {
        "query": "test query",
        "agent_role": "analyst",
        "user_id": "u1",
        "source_id": "reports",
        "sensitivity_level": "low",
        "session_id": str(uuid.uuid4()),
    }
    base.update(overrides)
    return base


# ── admin route access control ────────────────────────────────────────────────

class TestAdminAccessControl:
    def test_regular_key_cannot_create_tenant(self, client):
        r = client.post("/v1/admin/tenants", json={"name": "intruder_tenant"})
        assert r.status_code == 403

    def test_regular_key_cannot_list_tenants(self, client):
        r = client.get("/v1/admin/tenants")
        assert r.status_code == 403

    def test_regular_key_cannot_deactivate_tenant(self, client):
        r = client.delete("/v1/admin/tenants/ten_abc123")
        assert r.status_code == 403

    def test_superadmin_can_list_tenants(self, admin_client):
        r = admin_client.get("/v1/admin/tenants")
        assert r.status_code == 200
        assert isinstance(r.json(), list)


# ── tenant lifecycle ──────────────────────────────────────────────────────────

class TestTenantLifecycle:
    def test_create_tenant_returns_id_and_admin_key(self, admin_client):
        r = admin_client.post("/v1/admin/tenants", json={"name": "acme_corp"})
        assert r.status_code == 200
        body = r.json()
        assert "tenant_id" in body
        assert body["name"] == "acme_corp"
        assert body["admin_key"].startswith("apl_")
        assert "created_at" in body

    def test_created_tenant_appears_in_list(self, admin_client):
        admin_client.post("/v1/admin/tenants", json={"name": "list_me"})
        tenants = admin_client.get("/v1/admin/tenants").json()
        names = [t["name"] for t in tenants]
        assert "list_me" in names

    def test_create_tenant_admin_key_is_usable(self, policy_file, audit_db, admin_client):
        r = admin_client.post("/v1/admin/tenants", json={"name": "new_biz"})
        new_key = r.json()["admin_key"]
        app = create_app(policy_path=policy_file, audit_db=audit_db)
        new_client = TestClient(app, headers={"X-API-Key": new_key})
        assert new_client.get("/v1/policies").status_code == 200

    def test_deactivate_tenant_returns_ok(self, admin_client):
        tid = admin_client.post("/v1/admin/tenants", json={"name": "to_deactivate"}).json()["tenant_id"]
        r = admin_client.delete(f"/v1/admin/tenants/{tid}")
        assert r.status_code == 200
        assert r.json()["status"] == "deactivated"

    def test_deactivate_unknown_tenant_returns_404(self, admin_client):
        r = admin_client.delete("/v1/admin/tenants/ten_doesnotexist")
        assert r.status_code == 404

    def test_duplicate_tenant_name_is_rejected(self, admin_client):
        admin_client.post("/v1/admin/tenants", json={"name": "unique_name"})
        r = admin_client.post("/v1/admin/tenants", json={"name": "unique_name"})
        assert r.status_code in (400, 409, 422, 500)  # DB unique constraint


# ── tenant data isolation ─────────────────────────────────────────────────────

class TestTenantIsolation:
    def test_keys_scoped_to_tenant(self, policy_file, audit_db, admin_client):
        """Keys created by tenant A are not visible to tenant B."""
        # Create two tenants
        key_a = admin_client.post("/v1/admin/tenants", json={"name": "tenant_a"}).json()["admin_key"]
        key_b = admin_client.post("/v1/admin/tenants", json={"name": "tenant_b"}).json()["admin_key"]

        app = create_app(policy_path=policy_file, audit_db=audit_db)
        client_a = TestClient(app, headers={"X-API-Key": key_a})
        client_b = TestClient(app, headers={"X-API-Key": key_b})

        # A creates a key
        client_a.post("/v1/keys", json={"name": "a_key"})

        # B should not see A's key
        keys_b = client_b.get("/v1/keys").json()
        names_b = [k["name"] for k in keys_b]
        assert "a_key" not in names_b

    def test_audit_events_scoped_to_tenant(self, policy_file, audit_db, admin_client):
        """Audit events from tenant A are not visible to tenant B."""
        key_a = admin_client.post("/v1/admin/tenants", json={"name": "audit_a"}).json()["admin_key"]
        key_b = admin_client.post("/v1/admin/tenants", json={"name": "audit_b"}).json()["admin_key"]

        app = create_app(policy_path=policy_file, audit_db=audit_db)
        client_a = TestClient(app, headers={"X-API-Key": key_a})
        client_b = TestClient(app, headers={"X-API-Key": key_b})

        # A generates some events
        for _ in range(3):
            client_a.post("/v1/context/evaluate", json=_eval_payload())

        # B should see zero events
        r = client_b.get("/v1/audit/events")
        assert r.status_code == 200
        assert len(r.json()) == 0

    def test_stats_scoped_to_tenant(self, policy_file, audit_db, admin_client):
        """Stats endpoint returns counts only for the calling tenant."""
        key_a = admin_client.post("/v1/admin/tenants", json={"name": "stats_a"}).json()["admin_key"]
        key_b = admin_client.post("/v1/admin/tenants", json={"name": "stats_b"}).json()["admin_key"]

        app = create_app(policy_path=policy_file, audit_db=audit_db)
        client_a = TestClient(app, headers={"X-API-Key": key_a})
        client_b = TestClient(app, headers={"X-API-Key": key_b})

        client_a.post("/v1/context/evaluate", json=_eval_payload())
        client_a.post("/v1/context/evaluate", json=_eval_payload())

        stats_a = client_a.get("/v1/audit/stats").json()
        stats_b = client_b.get("/v1/audit/stats").json()

        assert stats_a["total_events"] == 2
        assert stats_b["total_events"] == 0
