"""
Tests for insaits/audit.py - Tamper-evident audit logger
"""

import json
import os
import tempfile
import pytest
from insa_its.audit import AuditLogger, GENESIS_HASH


@pytest.fixture
def audit_file(tmp_path):
    """Create a temporary audit file path."""
    return str(tmp_path / "test_audit.jsonl")


class TestAuditLoggerWrite:
    def test_write_creates_file(self, audit_file):
        audit = AuditLogger(audit_file)
        audit.write(
            event_type="message_processed",
            sender="agent1",
            receiver="agent2",
            had_anomaly=False,
            severity="info",
            action_taken="processed",
            message_hash="abc123",
        )
        assert os.path.exists(audit_file)

    def test_write_returns_entry(self, audit_file):
        audit = AuditLogger(audit_file)
        entry = audit.write(
            event_type="message_processed",
            sender="agent1",
            receiver="agent2",
            had_anomaly=True,
            severity="high",
            action_taken="quarantined",
            message_hash="def456",
        )
        assert entry["seq"] == 1
        assert entry["event"] == "message_processed"
        assert entry["sender"] == "agent1"
        assert entry["had_anomaly"] is True
        assert entry["severity"] == "high"
        assert entry["msg_hash"] == "def456"
        assert "hash" in entry
        assert entry["prev_hash"] == GENESIS_HASH

    def test_sequential_numbering(self, audit_file):
        audit = AuditLogger(audit_file)
        e1 = audit.write("e", "s", "r", False, "info", "p", "h1")
        e2 = audit.write("e", "s", "r", False, "info", "p", "h2")
        e3 = audit.write("e", "s", "r", True, "high", "q", "h3")
        assert e1["seq"] == 1
        assert e2["seq"] == 2
        assert e3["seq"] == 3

    def test_correlation_id(self, audit_file):
        audit = AuditLogger(audit_file)
        entry = audit.write(
            "e", "s", "r", False, "info", "p", "h1",
            correlation_id="corr-123",
        )
        assert entry["correlation_id"] == "corr-123"

    def test_no_correlation_id(self, audit_file):
        audit = AuditLogger(audit_file)
        entry = audit.write("e", "s", "r", False, "info", "p", "h1")
        assert "correlation_id" not in entry


class TestAuditLoggerHashChain:
    def test_hash_chain_links(self, audit_file):
        audit = AuditLogger(audit_file)
        e1 = audit.write("e", "s", "r", False, "info", "p", "h1")
        e2 = audit.write("e", "s", "r", False, "info", "p", "h2")
        assert e1["prev_hash"] == GENESIS_HASH
        assert e2["prev_hash"] == e1["hash"]
        assert e1["hash"] != e2["hash"]

    def test_hash_deterministic(self, audit_file):
        audit = AuditLogger(audit_file)
        e1 = audit.write("e", "s", "r", False, "info", "p", "h1")
        # Same content should produce different hash due to different timestamp
        # But the hash computation itself is deterministic for same input
        assert len(e1["hash"]) == 64  # SHA-256 hex


class TestAuditLoggerIntegrity:
    def test_verify_clean_log(self, audit_file):
        audit = AuditLogger(audit_file)
        for i in range(10):
            audit.write("e", "s", "r", i % 3 == 0, "info", "p", f"h{i}")
        assert audit.verify_integrity() is True

    def test_verify_empty_log(self, audit_file):
        audit = AuditLogger(audit_file)
        assert audit.verify_integrity() is True

    def test_detect_tampered_entry(self, audit_file):
        audit = AuditLogger(audit_file)
        for i in range(5):
            audit.write("e", "s", "r", False, "info", "p", f"h{i}")

        # Tamper with the file: modify a line
        with open(audit_file, "r") as f:
            lines = f.readlines()
        entry = json.loads(lines[2])
        entry["had_anomaly"] = True  # Tamper!
        lines[2] = json.dumps(entry) + "\n"
        with open(audit_file, "w") as f:
            f.writelines(lines)

        # New instance should detect tampering
        audit2 = AuditLogger(audit_file)
        assert audit2.verify_integrity() is False

    def test_detect_deleted_entry(self, audit_file):
        audit = AuditLogger(audit_file)
        for i in range(5):
            audit.write("e", "s", "r", False, "info", "p", f"h{i}")

        # Delete middle entry
        with open(audit_file, "r") as f:
            lines = f.readlines()
        del lines[2]
        with open(audit_file, "w") as f:
            f.writelines(lines)

        audit2 = AuditLogger(audit_file)
        assert audit2.verify_integrity() is False


class TestAuditLoggerResume:
    def test_resume_from_existing(self, audit_file):
        audit1 = AuditLogger(audit_file)
        e1 = audit1.write("e", "s", "r", False, "info", "p", "h1")
        e2 = audit1.write("e", "s", "r", False, "info", "p", "h2")

        # Create new instance that resumes
        audit2 = AuditLogger(audit_file)
        e3 = audit2.write("e", "s", "r", False, "info", "p", "h3")

        assert e3["seq"] == 3
        assert e3["prev_hash"] == e2["hash"]

        # Full chain should be valid
        assert audit2.verify_integrity() is True
