"""
Postgres backend tests.

Skipped automatically if DATABASE_URL is not set.
To run locally:
    docker compose up -d postgres
    DATABASE_URL=postgresql://autopil:autopil@localhost:5432/autopil pytest tests/test_postgres.py -v
"""

import os
import uuid

import pytest

from autopil.models import AuditEvent, Decision
from autopil.db import create_stores

DATABASE_URL = os.environ.get("DATABASE_URL")

pytestmark = pytest.mark.skipif(
    not DATABASE_URL,
    reason="DATABASE_URL not set — skipping Postgres tests",
)


@pytest.fixture(scope="module")
def pg_stores():
    audit_log, key_store = create_stores(database_url=DATABASE_URL)
    return audit_log, key_store


@pytest.fixture
def pg_audit(pg_stores):
    return pg_stores[0]


@pytest.fixture
def pg_keys(pg_stores):
    return pg_stores[1]


# ── AuditLog ──────────────────────────────────────────────────────────────────

class TestPostgresAuditLog:
    def test_record_and_retrieve(self, pg_audit):
        sid = str(uuid.uuid4())
        event = AuditEvent(
            event_id=str(uuid.uuid4()),
            session_id=sid,
            agent_role="analyst",
            user_id="u1",
            source_id="reports",
            query="test",
            decision=Decision.ALLOW,
            policy_name="test_policy",
            reason="ok",
            timestamp=__import__("datetime").datetime.utcnow(),
            context_hash="abc123",
        )
        pg_audit.record(event)
        events = pg_audit.get_session_events(sid)
        assert len(events) == 1
        assert events[0].event_id == event.event_id
        assert events[0].context_hash == "abc123"

    def test_session_isolation(self, pg_audit):
        sid_a, sid_b = str(uuid.uuid4()), str(uuid.uuid4())
        for sid in (sid_a, sid_b):
            pg_audit.record(AuditEvent(
                event_id=str(uuid.uuid4()), session_id=sid,
                agent_role="analyst", user_id="u1", source_id="reports",
                query="q", decision=Decision.ALLOW, policy_name="p",
                reason="ok", timestamp=__import__("datetime").datetime.utcnow(),
            ))
        assert len(pg_audit.get_session_events(sid_a)) == 1
        assert len(pg_audit.get_session_events(sid_b)) == 1

    def test_session_owner(self, pg_audit):
        sid = str(uuid.uuid4())
        pg_audit.record(AuditEvent(
            event_id=str(uuid.uuid4()), session_id=sid,
            agent_role="analyst", user_id="u1", source_id="reports",
            query="q", decision=Decision.ALLOW, policy_name="p",
            reason="ok", timestamp=__import__("datetime").datetime.utcnow(),
        ))
        assert pg_audit.get_session_owner(sid) == "analyst"

    def test_unknown_session_owner_is_none(self, pg_audit):
        assert pg_audit.get_session_owner(str(uuid.uuid4())) is None

    def test_get_all_events_returns_records(self, pg_audit):
        pg_audit.record(AuditEvent(
            event_id=str(uuid.uuid4()), session_id=str(uuid.uuid4()),
            agent_role="viewer", user_id="u2", source_id="reports",
            query="q", decision=Decision.DENY, policy_name="p",
            reason="denied", timestamp=__import__("datetime").datetime.utcnow(),
        ))
        events = pg_audit.get_all_events()
        assert len(events) >= 1


# ── KeyStore ──────────────────────────────────────────────────────────────────

class TestPostgresKeyStore:
    def test_create_and_validate(self, pg_keys):
        key_id, plaintext = pg_keys.create_key("pg_test")
        assert plaintext.startswith("apl_")
        assert pg_keys.validate(plaintext) == key_id

    def test_invalid_key_returns_none(self, pg_keys):
        assert pg_keys.validate("apl_notakey") is None

    def test_list_keys_no_plaintext(self, pg_keys):
        pg_keys.create_key("list_test")
        keys = pg_keys.list_keys()
        assert len(keys) >= 1
        for k in keys:
            assert "key_hash" not in k
            assert "key" not in k

    def test_revoke_blocks_validation(self, pg_keys):
        key_id, plaintext = pg_keys.create_key("revoke_test")
        assert pg_keys.validate(plaintext) is not None
        pg_keys.revoke(key_id)
        assert pg_keys.validate(plaintext) is None

    def test_revoke_unknown_returns_false(self, pg_keys):
        assert pg_keys.revoke("nonexistent_id") is False

    def test_count_increases(self, pg_keys):
        before = pg_keys.count()
        pg_keys.create_key("count_test")
        assert pg_keys.count() == before + 1
