"""Tests for the execution audit trail module.

Validates audit event construction, event type constants, and the
convenience helpers that record each stage of the execution pipeline.
"""
from services.shared.audit import (
    AUDIT_ORDER_CANCELLED,
    AUDIT_ORDER_DUPLICATE,
    AUDIT_ORDER_FILLED,
    AUDIT_ORDER_REJECTED,
    AUDIT_ORDER_SUBMITTED,
    AUDIT_POSITION_CLOSED,
    AUDIT_POSITION_OPENED,
    AUDIT_POSITION_UPDATED,
    AUDIT_RECOMMENDATION_GENERATED,
    AUDIT_RECOMMENDATION_SUPPRESSED,
    AUDIT_RISK_EVALUATED,
    AUDIT_RISK_REJECTED,
    AUDIT_TRADING_MODE_CHANGED,
)

# ---------------------------------------------------------------------------
# Event type constants
# ---------------------------------------------------------------------------


class TestAuditEventTypes:
    """Verify event type constants are well-formed and distinct."""

    def test_recommendation_events(self):
        assert AUDIT_RECOMMENDATION_GENERATED == "recommendation.generated"
        assert AUDIT_RECOMMENDATION_SUPPRESSED == "recommendation.suppressed"

    def test_risk_events(self):
        assert AUDIT_RISK_EVALUATED == "risk.evaluated"
        assert AUDIT_RISK_REJECTED == "risk.rejected"

    def test_order_events(self):
        assert AUDIT_ORDER_SUBMITTED == "order.submitted"
        assert AUDIT_ORDER_FILLED == "order.filled"
        assert AUDIT_ORDER_REJECTED == "order.rejected"
        assert AUDIT_ORDER_CANCELLED == "order.cancelled"
        assert AUDIT_ORDER_DUPLICATE == "order.duplicate_prevented"

    def test_position_events(self):
        assert AUDIT_POSITION_OPENED == "position.opened"
        assert AUDIT_POSITION_CLOSED == "position.closed"
        assert AUDIT_POSITION_UPDATED == "position.updated"

    def test_trading_mode_event(self):
        assert AUDIT_TRADING_MODE_CHANGED == "trading.mode_changed"

    def test_all_event_types_unique(self):
        all_types = [
            AUDIT_RECOMMENDATION_GENERATED,
            AUDIT_RECOMMENDATION_SUPPRESSED,
            AUDIT_RISK_EVALUATED,
            AUDIT_RISK_REJECTED,
            AUDIT_ORDER_SUBMITTED,
            AUDIT_ORDER_FILLED,
            AUDIT_ORDER_REJECTED,
            AUDIT_ORDER_CANCELLED,
            AUDIT_ORDER_DUPLICATE,
            AUDIT_POSITION_OPENED,
            AUDIT_POSITION_CLOSED,
            AUDIT_POSITION_UPDATED,
            AUDIT_TRADING_MODE_CHANGED,
        ]
        assert len(all_types) == len(set(all_types))

    def test_event_types_follow_dot_notation(self):
        """All event types should follow entity.action pattern."""
        all_types = [
            AUDIT_RECOMMENDATION_GENERATED,
            AUDIT_RECOMMENDATION_SUPPRESSED,
            AUDIT_RISK_EVALUATED,
            AUDIT_RISK_REJECTED,
            AUDIT_ORDER_SUBMITTED,
            AUDIT_ORDER_FILLED,
            AUDIT_ORDER_REJECTED,
            AUDIT_ORDER_CANCELLED,
            AUDIT_ORDER_DUPLICATE,
            AUDIT_POSITION_OPENED,
            AUDIT_POSITION_CLOSED,
            AUDIT_POSITION_UPDATED,
            AUDIT_TRADING_MODE_CHANGED,
        ]
        for t in all_types:
            assert "." in t, f"Event type {t} should use dot notation"
            parts = t.split(".")
            assert len(parts) == 2, f"Event type {t} should have exactly one dot"
            assert all(p for p in parts), f"Event type {t} has empty parts"


# ---------------------------------------------------------------------------
# Module imports and structure
# ---------------------------------------------------------------------------


class TestAuditModuleStructure:
    """Verify the audit module exports the expected functions."""

    def test_record_audit_event_exists(self):
        from services.shared.audit import record_audit_event
        assert callable(record_audit_event)

    def test_convenience_helpers_exist(self):
        from services.shared.audit import (
            audit_duplicate_prevented,
            audit_order_cancelled,
            audit_order_filled,
            audit_order_rejected,
            audit_order_submitted,
            audit_position_change,
            audit_recommendation_generated,
            audit_risk_evaluated,
            audit_trading_mode_changed,
        )
        for fn in [
            audit_recommendation_generated,
            audit_risk_evaluated,
            audit_order_submitted,
            audit_order_filled,
            audit_order_rejected,
            audit_order_cancelled,
            audit_duplicate_prevented,
            audit_position_change,
            audit_trading_mode_changed,
        ]:
            assert callable(fn)

    def test_query_helpers_exist(self):
        from services.shared.audit import (
            get_entity_audit_trail,
            get_order_audit_trail,
        )
        assert callable(get_order_audit_trail)
        assert callable(get_entity_audit_trail)


# ---------------------------------------------------------------------------
# Broker service audit integration
# ---------------------------------------------------------------------------


class TestBrokerServiceAuditImports:
    """Verify the broker service uses audit functions from the audit module."""

    def test_broker_service_has_audit_calls(self):
        """The broker service module should reference audit functions."""
        import inspect

        import services.adapters.broker_service as bs

        source = inspect.getsource(bs)
        assert "audit_order_submitted" in source
        assert "audit_order_filled" in source
        assert "audit_order_rejected" in source
        assert "audit_risk_evaluated" in source
        assert "audit_duplicate_prevented" in source
