"""Unittests for the wemeanyounoharm EMF + Claw3D / OpenClaw integration.

Run:
    cd /home/workspace/ghojualamanchu-v3
    python3 -m unittest tests.test_openclaw_integration -v
"""

import json
import sys
import unittest
from pathlib import Path

V1_BASE = Path("/home/workspace/ghojualamanchu")
V3_BASE = Path("/home/workspace/ghojualamanchu-v3")
SIGNAL_LOOP_DIR = V3_BASE / "data" / "signals"

sys.path.insert(0, str(V1_BASE))
sys.path.insert(0, str(V3_BASE))

from integrations.oscillation.flux_codec import (  # noqa: E402
    build_resonance_report,
    derive_oscillation_target,
    diff_target_vs_telemetry,
    write_all,
    ResonanceReport,
    OscillationTarget,
    Telemetry,
    FeedbackReport,
    PRESCRIPTION_TARGETS,
)

from integrations.openclaw.claw3d_emitter import build_agent_state  # noqa: E402
from integrations.openclaw.claw3d_consumer import (  # noqa: E402
    render_office_state,
    describe,
)


class FluxCodecTests(unittest.TestCase):

    def setUp(self):
        self.rr = build_resonance_report(0)
        self.ot = derive_oscillation_target(0)

    def test_resonance_has_required_fields(self):
        for f in ("beat", "timestamp", "earth_hz", "self_hz", "earth_phase",
                  "self_phase", "field_state", "trit"):
            self.assertIn(f, self.rr.to_dict(), f"missing {f}")
        self.assertIn(self.rr.field_state, ("DEAD", "CALM", "STIR", "STORM"))

    def test_resonance_trit_matches_phase(self):
        self.assertIn(self.rr.trit, (0, 1, 2))

    def test_oscillation_target_known_prescription(self):
        self.assertIn(self.ot.target_prescription,
                      ("attend", "alert", "hold", "calm", "stir", "storm",
                       "degraded"))
        self.assertIn(self.ot.trit, (0, 1, 2))
        self.assertGreaterEqual(self.ot.magnitude, 0.0)
        self.assertLessEqual(self.ot.magnitude, 1.5)

    def test_target_phase_trit_consistent(self):
        for name, spec in PRESCRIPTION_TARGETS.items():
            if spec["phase"] == "INHALE":
                self.assertEqual(spec["trit"], 0, name)
            elif spec["phase"] == "EXHALE":
                self.assertEqual(spec["trit"], 1, name)
            else:
                self.assertEqual(spec["trit"], 2, name)

    def test_diff_target_vs_telemetry_aligned(self):
        tlm = Telemetry(
            beat=0, timestamp=self.ot.timestamp, agent_id="t",
            action_taken=self.ot.target_prescription,
            self_trit=self.ot.trit, notes="aligned",
        )
        fb = diff_target_vs_telemetry(self.ot, tlm)
        self.assertTrue(fb.trit_match)
        self.assertGreaterEqual(fb.alignment_score, 0.5)
        self.assertEqual(fb.notes, "trit aligned")

    def test_diff_target_vs_telemetry_misaligned(self):
        wrong_trit = 0 if self.ot.trit != 0 else 1
        tlm = Telemetry(
            beat=0, timestamp=self.ot.timestamp, agent_id="t",
            action_taken="alert", self_trit=wrong_trit, notes="misaligned",
        )
        fb = diff_target_vs_telemetry(self.ot, tlm)
        self.assertFalse(fb.trit_match)
        self.assertIn("trit mismatch", fb.notes)

    def test_write_all_atomic(self):
        tlm = Telemetry(
            beat=0, timestamp=self.ot.timestamp, agent_id="t",
            action_taken=self.ot.target_prescription,
            self_trit=self.ot.trit, notes="ok",
        )
        fb = diff_target_vs_telemetry(self.ot, tlm)
        paths = write_all(self.rr, self.ot, tlm, fb)
        for name, p in paths.items():
            self.assertTrue(p.exists(), f"{name} not written to {p}")
            data = json.loads(p.read_text())
            self.assertIsInstance(data, dict)

    def test_signals_dir_persists(self):
        files = {"resonance_report", "oscillation_target", "telemetry",
                 "feedback_report"}
        found = {p.name.replace(".json", "") for p in SIGNAL_LOOP_DIR.glob("*.json")}
        self.assertTrue(files.issubset(found),
                        f"missing files: {files - found}")


class Claw3DEmitterTests(unittest.TestCase):

    def setUp(self):
        # ensure a fresh signal set so build_agent_state is deterministic
        rr = build_resonance_report(0)
        ot = derive_oscillation_target(0)
        tlm = Telemetry(
            beat=0, timestamp=ot.timestamp, agent_id="t",
            action_taken=ot.target_prescription, self_trit=ot.trit,
            notes="test",
        )
        fb = diff_target_vs_telemetry(ot, tlm)
        write_all(rr, ot, tlm, fb)
        from integrations.openclaw import claw3d_emitter  # noqa: E402
        claw3d_emitter.emit()
        self.state_path = SIGNAL_LOOP_DIR / "claw3d_agent_state.json"
        self.state = json.loads(self.state_path.read_text())

    def test_agent_state_schema(self):
        for k in ("type", "agent_id", "room_id", "ts", "beat", "field_state",
                  "trit", "phase", "magnitude", "prescription", "alignment",
                  "sources"):
            self.assertIn(k, self.state, f"missing {k}")
        self.assertEqual(self.state["type"], "agent_state")
        self.assertIn(self.state["field_state"], ("DEAD", "CALM", "STIR", "STORM"))
        self.assertIn(self.state["trit"], (0, 1, 2))
        self.assertIn(self.state["phase"], ("INHALE", "EXHALE", "HOLD"))
        self.assertGreaterEqual(self.state["alignment"], 0.0)
        self.assertLessEqual(self.state["alignment"], 1.0)

    def test_emit_no_network_by_default(self):
        # CLAW3D_GATEWAY_URL should be unset in the test env
        self.assertNotIn("_http_status", self.state)
        self.assertNotIn("_http_error", self.state)


class Claw3DConsumerTests(unittest.TestCase):

    def test_render_office_state_has_keys(self):
        state = render_office_state()
        for k in ("beat", "field_state", "phase", "trit", "prescription",
                  "magnitude", "alignment", "trit_match", "agent_id", "room_id",
                  "sources"):
            self.assertIn(k, state)

    def test_describe_returns_paragraph(self):
        state = render_office_state()
        text = describe(state)
        self.assertIsInstance(text, str)
        self.assertGreater(len(text), 30)
        self.assertIn(state.get("prescription", ""), text)


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