import unittest

from core.quote_state_machine import QuoteStateMachine
from core.rules import Rule, RuleContext, RuleEngine, RuleResult
from services.risk_service import RiskService


class _StubState:
    def __init__(self):
        self.pending_image_urls = []
        self.pending_requirements = []
        self.quote_phase = "idle"
        self.quote_ready_turns = 0


class RuleEngineTests(unittest.IsolatedAsyncioTestCase):
    async def test_rule_engine_priority_and_stop(self):
        async def pred_true(_ctx):
            return True

        async def act_first(_ctx):
            return RuleResult(matched=True, stop=True, action="first", payload={"x": 1})

        async def act_second(_ctx):
            return RuleResult(matched=True, stop=True, action="second", payload={"x": 2})

        engine = RuleEngine(
            [
                Rule(name="r2", priority=20, predicate=pred_true, action=act_second),
                Rule(name="r1", priority=10, predicate=pred_true, action=act_first),
            ]
        )
        out = await engine.run(RuleContext())
        self.assertTrue(out.matched)
        self.assertEqual(out.action, "first")
        self.assertEqual(out.payload["x"], 1)

    def test_quote_state_machine_transitions(self):
        sm = QuoteStateMachine(delay_turns=1)
        st = _StubState()
        st.pending_image_urls = ["u1"]
        sm.refresh(st)
        self.assertEqual(st.quote_phase, "collecting")
        self.assertTrue(sm.should_defer_batch_quote(st, mark_ready=True))
        self.assertEqual(st.quote_phase, "ready_to_quote")
        self.assertEqual(st.quote_ready_turns, 0)
        self.assertFalse(sm.should_defer_batch_quote(st, mark_ready=False))

    def test_risk_service_reject_text(self):
        svc = RiskService()
        self.assertIn("地图", svc.build_reject_text("map"))
        self.assertIn("政治", svc.build_reject_text("political"))
        self.assertIn("涉黄", svc.build_reject_text("sexual"))


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