"""
Tests for autopil.audit_log.AuditLog

Coverage:
  - Events are persisted and retrievable by session
  - get_all_events returns all events ordered by timestamp
  - get_session_owner returns the first agent_role for a session
  - Events from different sessions do not bleed into each other
  - Context hash is stored and retrieved correctly
  - Records are immutable (no update path)
"""

import uuid
from datetime import datetime

import pytest

from autopil.audit_log import AuditLog
from autopil.models import AuditEvent, Decision


def make_event(
    session_id: str,
    agent_role: str = "analyst",
    source_id: str = "reports",
    decision: Decision = Decision.ALLOW,
    context_hash: str | None = None,
) -> AuditEvent:
    return AuditEvent(
        event_id=str(uuid.uuid4()),
        session_id=session_id,
        agent_role=agent_role,
        user_id="u1",
        source_id=source_id,
        query="test query",
        decision=decision,
        policy_name="test_policy",
        reason="test reason",
        timestamp=datetime.utcnow(),
        context_hash=context_hash,
    )


# ── basic record and retrieval ────────────────────────────────────────────────

class TestRecordAndRetrieve:
    def test_record_and_retrieve_single_event(self, log):
        sid = str(uuid.uuid4())
        event = make_event(sid)
        log.record(event)
        events = log.get_session_events(sid)
        assert len(events) == 1
        assert events[0].event_id == event.event_id

    def test_all_fields_round_trip(self, log):
        sid   = str(uuid.uuid4())
        event = make_event(sid, agent_role="viewer", source_id="market_data",
                           decision=Decision.DENY, context_hash="abc123")
        log.record(event)
        result = log.get_session_events(sid)[0]

        assert result.session_id    == sid
        assert result.agent_role    == "viewer"
        assert result.source_id     == "market_data"
        assert result.decision      == Decision.DENY
        assert result.context_hash  == "abc123"
        assert result.policy_name   == "test_policy"

    def test_multiple_events_same_session(self, log):
        sid = str(uuid.uuid4())
        for i in range(5):
            log.record(make_event(sid, source_id=f"source_{i}"))
        events = log.get_session_events(sid)
        assert len(events) == 5

    def test_empty_session_returns_empty_list(self, log):
        assert log.get_session_events("nonexistent-session") == []


# ── session isolation ─────────────────────────────────────────────────────────

class TestSessionIsolation:
    def test_events_do_not_bleed_across_sessions(self, log):
        sid_a = str(uuid.uuid4())
        sid_b = str(uuid.uuid4())
        log.record(make_event(sid_a, source_id="source_a"))
        log.record(make_event(sid_b, source_id="source_b"))

        events_a = log.get_session_events(sid_a)
        events_b = log.get_session_events(sid_b)

        assert len(events_a) == 1
        assert events_a[0].source_id == "source_a"
        assert len(events_b) == 1
        assert events_b[0].source_id == "source_b"


# ── get_all_events ────────────────────────────────────────────────────────────

class TestGetAllEvents:
    def test_returns_all_events_across_sessions(self, log):
        for _ in range(3):
            log.record(make_event(str(uuid.uuid4())))
        assert len(log.get_all_events()) == 3

    def test_empty_db_returns_empty_list(self, log):
        assert log.get_all_events() == []


# ── session owner ─────────────────────────────────────────────────────────────

class TestSessionOwner:
    def test_first_agent_role_is_owner(self, log):
        sid = str(uuid.uuid4())
        log.record(make_event(sid, agent_role="analyst"))
        log.record(make_event(sid, agent_role="analyst"))
        assert log.get_session_owner(sid) == "analyst"

    def test_unknown_session_returns_none(self, log):
        assert log.get_session_owner("ghost-session") is None

    def test_owner_is_first_role_regardless_of_subsequent(self, log):
        """Even if a second role somehow records to the same session, owner stays first."""
        sid = str(uuid.uuid4())
        first = make_event(sid, agent_role="analyst")
        # Manually insert a later event with a different role (shouldn't happen in practice)
        second = make_event(sid, agent_role="viewer")
        log.record(first)
        log.record(second)
        assert log.get_session_owner(sid) == "analyst"


# ── context hash ──────────────────────────────────────────────────────────────

class TestContextHash:
    def test_context_hash_stored_for_allow(self, log):
        sid   = str(uuid.uuid4())
        event = make_event(sid, decision=Decision.ALLOW, context_hash="deadbeef12345678")
        log.record(event)
        result = log.get_session_events(sid)[0]
        assert result.context_hash == "deadbeef12345678"

    def test_context_hash_null_for_deny(self, log):
        sid   = str(uuid.uuid4())
        event = make_event(sid, decision=Decision.DENY, context_hash=None)
        log.record(event)
        result = log.get_session_events(sid)[0]
        assert result.context_hash is None
