# edited by glg
import json
import unittest

from pypos.modules.penjualan.services.transaksi_payload_service import TransaksiPayloadService
from pypos.modules.sinkronisasi.services.transaction_export_service import TransactionExportService


class FreeProdukRelationFlowTests(unittest.TestCase):
    def test_build_detail_data_split_paid_and_free_rows(self):
        service = TransaksiPayloadService()
        rows = [
            {
                "produk_id": "11702",
                "produk_nama": "Sayang Colek 145 gr isi 30",
                "harga_text": "1.950,00",
                "jumlah_text": "10",
                "satuan": "pcs",
                "diskon_text": "0",
                "produk_jenis": "free_produk",
                "free_qty": 5,
                "free_produk_id": "11702",
                "free_produk_nama": "Sayang Colek 145 gr isi 30",
            }
        ]

        detail_data, total_harga = service.build_detail_data(rows)
        self.assertEqual(total_harga, 19500)
        self.assertEqual(len(detail_data), 2)

        paid_row = detail_data[0]
        free_row = detail_data[1]

        self.assertEqual(paid_row.produk_jenis, "invoice")
        self.assertEqual(int(paid_row.produk_ord_jml), 10)
        self.assertEqual(int(paid_row.produk_ord_hrg), 1950)

        self.assertEqual(free_row.produk_jenis, "free_produk")
        self.assertEqual(int(free_row.produk_ord_jml), 5)
        self.assertEqual(int(free_row.produk_ord_hrg), 0)
        self.assertEqual(int(free_row.parent_id), 11702)

        relasi = json.loads(str(free_row.ext_intext or "{}"))
        self.assertIn("free_relasi", relasi)
        self.assertEqual(int(relasi["free_relasi"]["source_produk_id"]), 11702)
        self.assertEqual(int(relasi["free_relasi"]["free_qty"]), 5)

    def test_build_detail_data_free_selected_without_quota_keeps_paid_only(self):
        service = TransaksiPayloadService()
        rows = [
            {
                "produk_id": "11702",
                "produk_nama": "Sayang Colek 145 gr isi 30",
                "harga_text": "1.950,00",
                "jumlah_text": "10",
                "satuan": "pcs",
                "diskon_text": "0",
                "produk_jenis": "free_produk",
                "free_qty": 0,
                "free_produk_id": "11702",
                "free_produk_nama": "Sayang Colek 145 gr isi 30",
            }
        ]

        detail_data, total_harga = service.build_detail_data(rows)
        self.assertEqual(total_harga, 19500)
        self.assertEqual(len(detail_data), 1)
        self.assertEqual(detail_data[0].produk_jenis, "invoice")

    def test_legacy_free_builder_uses_relasi_source_produk(self):
        service = TransactionExportService()
        detail_rows = [
            {
                "id": 123,
                "produk_id": "11702",
                "produk_nama": "Bonus Produk",
                "produk_jenis": "free_produk",
                "valid_qty": 2,
                "ext_intext": json.dumps(
                    {
                        "free_relasi": {
                            "source_produk_id": 11174,
                            "source_produk_nama": "Produk Pemicu",
                            "source_qty": 10,
                            "free_produk_id": 11702,
                            "free_produk_nama": "Bonus Produk",
                            "free_qty": 2,
                        }
                    }
                ),
            }
        ]
        produk_map = {
            "11174": {"nama": "Produk Pemicu"},
            "11702": {"nama": "Bonus Produk"},
        }
        diskon_map = {
            "11174": {
                "free_produk_id": "11702",
                "free_produk_nama": "Bonus Produk",
                "kelipatan": 1,
                "minim": 5,
                "quota_global": 20,
                "quota_used": 3,
            }
        }

        payload = service._build_legacy_free_items_payload(
            detail_rows=detail_rows,
            produk_map=produk_map,
            diskon_map=diskon_map,
            dtime_value="2026-03-05 12:00:00",
        )

        self.assertIn("11174", payload)
        event_data = list(payload["11174"].values())[0]
        self.assertEqual(event_data["ori_produk_id"], "11174")
        self.assertEqual(event_data["ori_produk_nama"], "Produk Pemicu")
        self.assertEqual(int(event_data["produk_beli_jml"]), 10)
        self.assertEqual(event_data["free_produk_id"], "11702")
        self.assertEqual(int(event_data["free_qty"]), 2)

    def test_build_detail_data_uses_ui_subtotal_as_source_of_truth(self):
        service = TransaksiPayloadService()
        rows = [
            {
                "produk_id": "11174",
                "produk_nama": "AOKA MIX",
                "harga_text": "1.900,00",
                "subtotal_text": "432.000,00",
                "jumlah_text": "240",
                "satuan": "pcs",
                "diskon_text": "5,26",
                "diskon_rp_text": "100,00",
                "produk_jenis": "invoice",
            }
        ]

        detail_data, total_harga = service.build_detail_data(rows)
        self.assertEqual(len(detail_data), 1)
        self.assertEqual(total_harga, 432000)

    def test_build_detail_data_fallback_when_ui_subtotal_missing(self):
        service = TransaksiPayloadService()
        rows = [
            {
                "produk_id": "11174",
                "produk_nama": "AOKA MIX",
                "harga_text": "1.900,00",
                "jumlah_text": "240",
                "satuan": "pcs",
                "diskon_text": "5,26",
                "diskon_rp_text": "100,00",
                "produk_jenis": "invoice",
            }
        ]

        detail_data, total_harga = service.build_detail_data(rows)
        self.assertEqual(len(detail_data), 1)
        # fallback lama: hitung dari persen diskon
        self.assertEqual(total_harga, 432014)

    # edited by glg
    def test_build_detail_data_emit_warning_callback_saat_row_invalid_non_strict(self):
        service = TransaksiPayloadService()
        rows = [
            {
                "produk_id": "",
                "produk_nama": "Produk Invalid",
                "harga_text": "10.000,00",
                "jumlah_text": "1",
                "produk_jenis": "invoice",
            }
        ]
        events = []
        detail_data, total_harga = service.build_detail_data(
            rows,
            on_row_error=lambda event: events.append(dict(event or {})),
            strict_mode=False,
            error_log_limit=5,
        )
        self.assertEqual(detail_data, [])
        self.assertEqual(total_harga, 0)
        self.assertEqual(len(events), 1)
        self.assertEqual(str(events[0].get("stage")), "build_detail_data")
        self.assertIn("invalid_produk_id", str(events[0].get("reason") or ""))

    # edited by glg
    def test_build_detail_data_strict_mode_fail_fast_saat_row_invalid(self):
        service = TransaksiPayloadService()
        rows = [
            {
                "produk_id": "",
                "produk_nama": "Produk Invalid",
                "harga_text": "10.000,00",
                "jumlah_text": "1",
                "produk_jenis": "invoice",
            }
        ]
        with self.assertRaises(ValueError):
            service.build_detail_data(rows, strict_mode=True)


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