"""Tests for the hash-chained audit log."""

import json

from langchain_nobulex.audit import GENESIS_HASH, AuditLog, _compute_hash


class TestAuditLog:
    def test_empty_log(self):
        log = AuditLog()
        assert len(log) == 0
        assert log.get_log() == []

    def test_add_single_entry(self):
        log = AuditLog()
        entry = log.add_entry(
            action="read",
            params={"file": "data.csv"},
            allowed=True,
            matching_rule="permit read",
            timestamp="2026-01-01T00:00:00+00:00",
        )
        assert entry.action == "read"
        assert entry.allowed is True
        assert entry.prev_hash == GENESIS_HASH
        assert len(entry.hash) == 64  # SHA-256 hex
        assert len(log) == 1

    def test_hash_chain_links(self):
        log = AuditLog()
        e1 = log.add_entry(
            action="read", params={}, allowed=True,
            matching_rule="permit read",
            timestamp="2026-01-01T00:00:00+00:00",
        )
        e2 = log.add_entry(
            action="write", params={}, allowed=True,
            matching_rule="default:allow",
            timestamp="2026-01-01T00:00:01+00:00",
        )
        assert e2.prev_hash == e1.hash
        assert e1.prev_hash == GENESIS_HASH

    def test_hash_deterministic(self):
        log1 = AuditLog()
        log2 = AuditLog()
        e1 = log1.add_entry(
            action="read", params={"x": 1}, allowed=True,
            matching_rule="r1", timestamp="t1",
        )
        e2 = log2.add_entry(
            action="read", params={"x": 1}, allowed=True,
            matching_rule="r1", timestamp="t1",
        )
        assert e1.hash == e2.hash

    def test_hash_changes_with_different_data(self):
        log1 = AuditLog()
        log2 = AuditLog()
        e1 = log1.add_entry(
            action="read", params={}, allowed=True,
            matching_rule="r1", timestamp="t1",
        )
        e2 = log2.add_entry(
            action="read", params={}, allowed=False,
            matching_rule="r1", timestamp="t1",
        )
        assert e1.hash != e2.hash

    def test_export_json(self):
        log = AuditLog()
        log.add_entry(
            action="read", params={"file": "a.txt"}, allowed=True,
            matching_rule="permit read", timestamp="2026-01-01T00:00:00+00:00",
        )
        exported = json.loads(log.export_json())
        assert len(exported) == 1
        assert exported[0]["action"] == "read"
        assert "hash" in exported[0]

    def test_export_dicts(self):
        log = AuditLog()
        log.add_entry(
            action="read", params={}, allowed=True,
            matching_rule="r1", timestamp="t1",
        )
        dicts = log.export_dicts()
        assert isinstance(dicts, list)
        assert isinstance(dicts[0], dict)
        assert dicts[0]["action"] == "read"

    def test_get_log_returns_copy(self):
        log = AuditLog()
        log.add_entry(
            action="read", params={}, allowed=True,
            matching_rule="r1", timestamp="t1",
        )
        entries = log.get_log()
        entries.clear()
        assert len(log) == 1  # original unaffected


class TestComputeHash:
    def test_genesis_hash(self):
        assert len(GENESIS_HASH) == 64

    def test_compute_hash_deterministic(self):
        h1 = _compute_hash("prev", "ts", "act", {"k": "v"}, True, "rule")
        h2 = _compute_hash("prev", "ts", "act", {"k": "v"}, True, "rule")
        assert h1 == h2

    def test_compute_hash_sensitive_to_input(self):
        h1 = _compute_hash("prev", "ts", "act", {"k": "v"}, True, "rule")
        h2 = _compute_hash("prev", "ts", "act", {"k": "v"}, False, "rule")
        assert h1 != h2
