import unittest

from pypos.modules.penjualan.services.settlement_orchestrator_service import SettlementOrchestratorService


class _FakeModel:
    def __init__(self):
        self._last_print_ids = []
        self.last_simpan_kwargs = {}
        self.get_ids_call_count = 0
        self.last_set_settlement_ids = []

    def get_admin_settlement_status(self, admin_name):
        return {"id": 182, "nama_login": str(admin_name or ""), "oto_settlement": 1}

    def verifikasi_admin(self, _admin_name, _password):
        return True

    def simpan_settlement(self, **kwargs):
        self.last_simpan_kwargs = dict(kwargs or {})
        return "ST-TEST-001"

    def get_transaksi_ids_belum_settle(self, **_kwargs):
        self.get_ids_call_count += 1
        return [11, 12]

    def set_settlement(self, transaksi_ids, *_args, **_kwargs):
        self.last_set_settlement_ids = list(transaksi_ids or [])
        return True

    def hitung_total_per_metode_by_ids(self, transaksi_ids):
        self._last_print_ids = list(transaksi_ids or [])
        return {"Tunai": 30000.0, "Non Tunai": 0.0}

    def get_transaksi_by_ids(self, transaksi_ids):
        return [
            {"id": 11, "nomer": "INV-11", "total": 10000, "metode": "Tunai"},
            {"id": 12, "nomer": "INV-12", "total": 20000, "metode": "Tunai"},
        ]


class _FakeModelAtomic(_FakeModel):
    def __init__(self):
        super().__init__()
        self.execute_atomic_called = False

    def execute_settlement_atomic(self, **kwargs):
        self.execute_atomic_called = True
        self.last_simpan_kwargs = dict(kwargs or {})
        return {
            "ok": True,
            "counter": "ST-ATOMIC-001",
            "transaksi_ids": [11, 12],
        }

    def simpan_settlement(self, **kwargs):
        raise AssertionError("fallback simpan_settlement tidak boleh dipanggil pada jalur atomic")

    def set_settlement(self, transaksi_ids, *_args, **_kwargs):
        raise AssertionError("fallback set_settlement tidak boleh dipanggil pada jalur atomic")


class _FakePrintController:
    def __init__(self):
        self.payload = None

    def print_settlement(self, counter, kasir_nama, shift, total_dict, transaksi_list):
        self.payload = {
            "counter": counter,
            "kasir_nama": kasir_nama,
            "shift": shift,
            "total_dict": total_dict,
            "transaksi_list": transaksi_list,
        }
        return True


# edited by glg
class SettlementOrchestratorServiceTests(unittest.TestCase):
    def test_print_settlement_scope_berdasarkan_ids_batch(self):
        fake_model = _FakeModel()
        fake_print = _FakePrintController()
        service = SettlementOrchestratorService(fake_model, fake_print)

        result = service.execute_settlement(
            transaksi_data=[{"tanggal": "2026-03-06", "kasir": "kasir glg", "total": 30000}],
            total_disetor=30000,
            admin_name="admglg",
            user_info={"id": 1, "nama": "kasir glg", "shift": "1", "cabang_id": 100, "cabang_nama": "Cabang A"},
        )

        self.assertTrue(bool(result.get("ok")))
        self.assertEqual(fake_model._last_print_ids, [11, 12])
        self.assertEqual(int(fake_model.get_ids_call_count), 1)
        self.assertEqual(fake_model.last_set_settlement_ids, [11, 12])
        self.assertEqual(int(fake_model.last_simpan_kwargs.get("approval_id") or 0), 182)
        self.assertEqual(str(fake_model.last_simpan_kwargs.get("approval_nama") or ""), "admglg")
        self.assertEqual(fake_model.last_simpan_kwargs.get("transaksi_ids_override"), [11, 12])
        self.assertTrue(str(fake_model.last_simpan_kwargs.get("trace_id") or "").startswith("settlement-"))
        self.assertIsNotNone(fake_print.payload)
        self.assertEqual(fake_print.payload["total_dict"], {"Tunai": 30000.0, "Non Tunai": 0.0})
        self.assertEqual(len(fake_print.payload["transaksi_list"]), 2)
        self.assertTrue(str(result.get("trace_id") or "").startswith("settlement-"))

    def test_execute_settlement_memakai_executor_atomik_bila_tersedia(self):
        fake_model = _FakeModelAtomic()
        fake_print = _FakePrintController()
        service = SettlementOrchestratorService(fake_model, fake_print)

        result = service.execute_settlement(
            transaksi_data=[{"tanggal": "2026-03-06", "kasir": "kasir glg", "total": 30000}],
            total_disetor=30000,
            admin_name="admglg",
            user_info={"id": 1, "nama": "kasir glg", "shift": "1", "cabang_id": 100, "cabang_nama": "Cabang A"},
        )

        self.assertTrue(bool(result.get("ok")))
        self.assertTrue(bool(fake_model.execute_atomic_called))
        self.assertEqual(fake_model.last_simpan_kwargs.get("admin"), "admglg")
        self.assertEqual(fake_model.last_simpan_kwargs.get("transaksi_ids_override"), [11, 12])
        self.assertTrue(str(fake_model.last_simpan_kwargs.get("trace_id") or "").startswith("settlement-"))
        self.assertEqual(result.get("counter"), "ST-ATOMIC-001")
        self.assertTrue(str(result.get("trace_id") or "").startswith("settlement-"))


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