# edited by glg
import unittest

from pypos.modules.dashboard.controllers.dashboard_controller import DashboardController


class _DummyView:
    pass


class _DummyAppController:
    pass


class _NetworkGateAllowStub:
    def can_run(self, process, force_probe=False):
        _ = (process, force_probe)
        return {
            "allow": True,
            "state": "ONLINE_STABLE",
            "reason": "test_allow",
            "server_online": True,
            "internet_online": True,
        }


class _SettlementDirectServiceStub:
    def __init__(self, responses=None, enabled=True):
        self.responses = list(responses or [])
        self.enabled_getter = lambda: bool(enabled)
        self.calls = []

    def send_settlement(self, payload):
        self.calls.append(dict(payload or {}))
        if self.responses:
            return dict(self.responses.pop(0))
        return {
            "attempted": True,
            "ok": False,
            "status_code": 0,
            "reason_code": "timeout",
            "error": "timeout",
            "retryable": True,
        }


class DashboardSettlementCloseGuardTests(unittest.TestCase):
    def _build_controller(self):
        ctrl = DashboardController(_DummyView(), _DummyAppController())
        # edited by glg
        # Hindari dependency probe jaringan real pada unit-test guard settlement.
        ctrl.network_orchestrator = _NetworkGateAllowStub()
        return ctrl

    def test_guard_state_non_blocking_when_empty(self):
        ctrl = self._build_controller()
        state = ctrl.get_settlement_delivery_guard_state()
        self.assertFalse(bool(state.get("blocking")))
        self.assertFalse(bool(state.get("inflight")))
        self.assertEqual(int(state.get("unsent_count") or 0), 0)

    def test_guard_state_blocking_when_unsent_exists(self):
        ctrl = self._build_controller()
        marked = ctrl._mark_settlement_unsent(
            settlement_result={"counter": "ST-1", "transaksi_ids": [1, 2]},
            error="offline",
            status_code=0,
            reason_code="offline",
            retryable=True,
        )
        self.assertTrue(marked)
        state = ctrl.get_settlement_delivery_guard_state()
        self.assertTrue(bool(state.get("blocking")))
        self.assertEqual(int(state.get("unsent_count") or 0), 1)
        self.assertEqual(
            str((((state.get("unsent_items") or [])[0] or {}).get("settlement_result") or {}).get("counter") or ""),
            "ST-1",
        )

    def test_retry_pending_settlement_clears_unsent_on_success(self):
        ctrl = self._build_controller()
        ctrl._mark_settlement_unsent(
            settlement_result={"counter": "ST-2", "transaksi_ids": [10]},
            error="offline",
            status_code=0,
            reason_code="offline",
            retryable=True,
        )
        service = _SettlementDirectServiceStub(
            responses=[
                {
                    "attempted": True,
                    "ok": True,
                    "status_code": 200,
                    "reason_code": "success",
                    "error": "",
                    "retryable": False,
                }
            ],
            enabled=True,
        )
        ctrl._settlement_direct_service = service

        result = ctrl.retry_pending_settlement_direct_delivery(max_items=3)
        self.assertEqual(int(result.get("attempted") or 0), 1)
        self.assertEqual(int(result.get("success") or 0), 1)
        self.assertEqual(int(result.get("remaining") or 0), 0)

        state = ctrl.get_settlement_delivery_guard_state()
        self.assertFalse(bool(state.get("blocking")))

    def test_retry_pending_settlement_keeps_unsent_on_failure(self):
        ctrl = self._build_controller()
        ctrl._mark_settlement_unsent(
            settlement_result={"counter": "ST-3", "transaksi_ids": [11]},
            error="offline",
            status_code=0,
            reason_code="offline",
            retryable=True,
        )
        service = _SettlementDirectServiceStub(
            responses=[
                {
                    "attempted": True,
                    "ok": False,
                    "status_code": 503,
                    "reason_code": "server_error",
                    "error": "server busy",
                    "retryable": True,
                }
            ],
            enabled=True,
        )
        ctrl._settlement_direct_service = service

        result = ctrl.retry_pending_settlement_direct_delivery(max_items=1)
        self.assertEqual(int(result.get("attempted") or 0), 1)
        self.assertEqual(int(result.get("failed") or 0), 1)
        self.assertEqual(int(result.get("remaining") or 0), 1)

        state = ctrl.get_settlement_delivery_guard_state()
        self.assertTrue(bool(state.get("blocking")))
        self.assertEqual(int(state.get("unsent_count") or 0), 1)
