import datetime
import hashlib
import json
import sys
from pathlib import Path

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from core.outbox_writer import _canonical_hash, write_event


class TestCanonicalHash:
    def test_deterministic(self):
        event = {"b": 2, "a": 1}
        h1 = _canonical_hash(event)
        h2 = _canonical_hash(event)
        assert h1 == h2

    def test_order_independent(self):
        h1 = _canonical_hash({"a": 1, "b": 2})
        h2 = _canonical_hash({"b": 2, "a": 1})
        assert h1 == h2

    def test_is_sha256_hex(self):
        h = _canonical_hash({"key": "val"})
        assert len(h) == 64
        assert all(c in "0123456789abcdef" for c in h)

    def test_different_events_different_hash(self):
        h1 = _canonical_hash({"a": 1})
        h2 = _canonical_hash({"a": 2})
        assert h1 != h2


class TestWriteEvent:
    def _sample_event(self):
        return {
            "contractId": "test-contract-001",
            "eventType": "CONFIDENCE_COMPUTED",
            "ts": "2026-07-22T00:00:00Z",
            "environment": "dev",
            "stack": "s3",
            "score": 0.85,
            "band": "pass",
            "prev_event_hash": "GENESIS",
        }

    def test_write_event_with_mock_dynamodb(self):
        from moto import mock_aws

        import boto3

        with mock_aws():
            dyn = boto3.client("dynamodb", region_name="us-east-1")
            dyn.create_table(
                TableName="acdl-outbox",
                KeySchema=[
                    {"AttributeName": "contractId", "KeyType": "HASH"},
                    {"AttributeName": "eventType#eventTs", "KeyType": "RANGE"},
                ],
                AttributeDefinitions=[
                    {"AttributeName": "contractId", "AttributeType": "S"},
                    {"AttributeName": "eventType#eventTs", "AttributeType": "S"},
                ],
                BillingMode="PAY_PER_REQUEST",
            )

            event = self._sample_event()
            item = write_event(event, outbox_table="acdl-outbox", region="us-east-1")

            assert item["contractId"]["S"] == "test-contract-001"
            assert item["prev_event_hash"]["S"] == "GENESIS"
            assert "hash" in item
            assert len(item["hash"]["S"]) == 64
            assert "expire_at" in item

    def test_write_event_hash_matches_canonical(self):
        from moto import mock_aws

        import boto3

        with mock_aws():
            dyn = boto3.client("dynamodb", region_name="us-east-1")
            dyn.create_table(
                TableName="acdl-outbox",
                KeySchema=[
                    {"AttributeName": "contractId", "KeyType": "HASH"},
                    {"AttributeName": "eventType#eventTs", "KeyType": "RANGE"},
                ],
                AttributeDefinitions=[
                    {"AttributeName": "contractId", "AttributeType": "S"},
                    {"AttributeName": "eventType#eventTs", "AttributeType": "S"},
                ],
                BillingMode="PAY_PER_REQUEST",
            )

            event = self._sample_event()
            item = write_event(event, outbox_table="acdl-outbox", region="us-east-1")
            expected_hash = _canonical_hash(event)
            assert item["hash"]["S"] == expected_hash

    def test_write_event_persists_to_dynamodb(self):
        from moto import mock_aws

        import boto3

        with mock_aws():
            dyn = boto3.client("dynamodb", region_name="us-east-1")
            dyn.create_table(
                TableName="acdl-outbox",
                KeySchema=[
                    {"AttributeName": "contractId", "KeyType": "HASH"},
                    {"AttributeName": "eventType#eventTs", "KeyType": "RANGE"},
                ],
                AttributeDefinitions=[
                    {"AttributeName": "contractId", "AttributeType": "S"},
                    {"AttributeName": "eventType#eventTs", "AttributeType": "S"},
                ],
                BillingMode="PAY_PER_REQUEST",
            )

            event = self._sample_event()
            write_event(event, outbox_table="acdl-outbox", region="us-east-1")

            resp = dyn.get_item(
                TableName="acdl-outbox",
                Key={
                    "contractId": {"S": "test-contract-001"},
                    "eventType#eventTs": {"S": "CONFIDENCE_COMPUTED#2026-07-22T00:00:00Z"},
                },
            )
            assert "Item" in resp
            assert resp["Item"]["band"]["S"] == "pass"