import unittest

from hiveos.tei import TEI_VERSION, validate_tei_batch, validate_tei_event


def _valid_event():
    return {
        "tei_version": TEI_VERSION,
        "event_id": "evt-001",
        "event_type": "agent.step",
        "occurred_at_ms": 1772800000000,
        "run_id": "observe-run:abc123",
        "source": {"framework": "example-framework", "emitter": "adapter.v1"},
        "payload": {"note": "ok"},
    }


class TeiContractTests(unittest.TestCase):
    def test_validate_tei_event_accepts_minimum_valid_event(self):
        result = validate_tei_event(_valid_event())
        self.assertTrue(result["ok"])
        self.assertEqual([], result["errors"])
        self.assertEqual("agent.step", result["normalized"]["event_type"])
        self.assertEqual("agent.step", result["normalized"]["canonical_event_type"])
        self.assertEqual("unknown", result["normalized"]["status"])

    def test_validate_tei_event_maps_canonical_event_type(self):
        event = _valid_event()
        event["event_type"] = "observe_tool_call_end"
        event["outcome"] = "success"
        result = validate_tei_event(event)
        self.assertTrue(result["ok"])
        self.assertEqual("tool.result", result["normalized"]["canonical_event_type"])
        self.assertEqual("success", result["normalized"]["status"])

    def test_validate_tei_event_rejects_missing_required_field(self):
        event = _valid_event()
        event.pop("event_type")
        result = validate_tei_event(event)
        self.assertFalse(result["ok"])
        self.assertTrue(any("missing required field: event_type" in err for err in result["errors"]))

    def test_validate_tei_event_rejects_invalid_timestamp(self):
        event = _valid_event()
        event["occurred_at_ms"] = "not-a-number"
        result = validate_tei_event(event)
        self.assertFalse(result["ok"])
        self.assertTrue(any("occurred_at_ms must be an integer" in err for err in result["errors"]))

    def test_validate_tei_event_rejects_missing_source_framework(self):
        event = _valid_event()
        event["source"] = {"emitter": "adapter.v1"}
        result = validate_tei_event(event)
        self.assertFalse(result["ok"])
        self.assertTrue(any("source.framework must be a non-empty string" in err for err in result["errors"]))

    def test_validate_tei_event_rejects_non_object_payload(self):
        event = _valid_event()
        event["payload"] = "raw text"
        result = validate_tei_event(event)
        self.assertFalse(result["ok"])
        self.assertTrue(any("payload must be an object" in err for err in result["errors"]))

    def test_validate_tei_event_rejects_non_positive_attempt(self):
        event = _valid_event()
        event["attempt"] = 0
        result = validate_tei_event(event)
        self.assertFalse(result["ok"])
        self.assertTrue(any("attempt must be >= 1" in err for err in result["errors"]))

    def test_validate_tei_event_version_mismatch_obeys_strict_flag(self):
        event = _valid_event()
        event["tei_version"] = "0.0"
        strict_result = validate_tei_event(event, strict_version=True)
        permissive_result = validate_tei_event(event, strict_version=False)
        self.assertFalse(strict_result["ok"])
        self.assertTrue(any("unsupported tei_version" in err for err in strict_result["errors"]))
        self.assertTrue(permissive_result["ok"])

    def test_validate_tei_batch_reports_per_item_status(self):
        valid = _valid_event()
        invalid = _valid_event()
        invalid["source"] = "bad"
        result = validate_tei_batch([valid, invalid])
        self.assertFalse(result["ok"])
        self.assertEqual(2, result["total"])
        self.assertEqual(1, result["valid"])
        self.assertEqual(1, result["invalid"])
        self.assertEqual(2, len(result["items"]))
        self.assertTrue(result["items"][0]["ok"])
        self.assertFalse(result["items"][1]["ok"])


if __name__ == "__main__":
    unittest.main()
