from typing import Any, Callable, Dict, Tuple

# edited by glg


class TransactionExportSettlementPaymentUtils:
    @staticmethod
    def ensure_entry(grouped: Dict[str, Dict[str, Any]], account_id: str, metode: str, bank_name: str):
        target = grouped if isinstance(grouped, dict) else {}
        key = str(account_id or "").strip() or "0"
        if key not in target:
            target[key] = {
                "bank": str(bank_name or "").strip(),
                "account_id": key,
                "metode_pembayaran": str(metode or "cash"),
                "return_nilai": 0,
                "jml_payment": 0,
                "nilai_diterima": 0,
                "nilai_settlement": 0,
                "selisih_settlement": 0,
            }
        return target[key]

    @staticmethod
    def normalize_tunai_non_tunai(
        netto_tagihan: int,
        total_bayar_raw: int,
        non_tunai_raw: int,
    ) -> Tuple[int, int]:
        total_bayar = int(max(0, total_bayar_raw or 0))
        non_tunai = int(max(0, non_tunai_raw or 0))
        if total_bayar > 0 and non_tunai > total_bayar:
            non_tunai = total_bayar
        tunai = max(0, total_bayar - non_tunai)

        if total_bayar <= 0:
            return 0, 0

        target_total = min(max(0, int(netto_tagihan or 0)), total_bayar)
        scale = min(1.0, float(target_total) / float(total_bayar))
        tunai_scaled = int(round(float(tunai) * scale))
        non_tunai_scaled = int(round(float(non_tunai) * scale))
        allocated = tunai_scaled + non_tunai_scaled
        diff = int(target_total - allocated)
        if diff != 0:
            if non_tunai >= tunai:
                non_tunai_scaled = max(0, non_tunai_scaled + diff)
            else:
                tunai_scaled = max(0, tunai_scaled + diff)
        return int(max(0, tunai_scaled)), int(max(0, non_tunai_scaled))

    @staticmethod
    def resolve_return_nominal(return_row: Dict[str, Any], to_int_fn: Callable[[Any, int], int]) -> int:
        row = return_row if isinstance(return_row, dict) else {}
        return max(
            0,
            int(
                to_int_fn(
                    row.get("refund_amount"),
                    to_int_fn(row.get("total_return"), 0),
                )
            ),
        )

    @staticmethod
    def allocate_return_value(
        grouped: Dict[str, Dict[str, Any]],
        *,
        account_id: str,
        nominal: int,
        metode: str,
        bank_name: str,
        to_int_fn: Callable[[Any, int], int],
    ) -> None:
        nominal_val = max(0, int(to_int_fn(nominal, 0)))
        if nominal_val <= 0:
            return
        entry = TransactionExportSettlementPaymentUtils.ensure_entry(
            grouped,
            account_id=str(account_id),
            metode=metode,
            bank_name=bank_name,
        )
        entry["return_nilai"] = int(to_int_fn(entry.get("return_nilai"), 0)) + nominal_val

    @staticmethod
    def apply_payment_legacy_aliases(
        target_payload: Dict[str, Any],
        *,
        to_int_fn: Callable[[Any, int], int],
    ) -> Dict[str, Any]:
        target = target_payload if isinstance(target_payload, dict) else {}
        nilai_diterima = max(0, int(to_int_fn(target.get("nilai_diterima"), 0)))
        nilai_settlement = max(0, int(to_int_fn(target.get("nilai_settlement"), 0)))
        selisih_settlement = int(
            to_int_fn(
                target.get("selisih_settlement"),
                nilai_settlement - nilai_diterima,
            )
        )
        diskon_produk = max(0, int(to_int_fn(target.get("diskon_produk"), 0)))
        diskon_tambahan = max(
            0,
            int(
                to_int_fn(
                    target.get("diskon_tambahan_nilai"),
                    to_int_fn(target.get("add_disc"), 0),
                )
            ),
        )

        target["harga"] = int(nilai_settlement)
        target["harga_nett2"] = int(nilai_settlement)
        target["grand_total"] = int(nilai_settlement)
        target["tagihan"] = int(nilai_settlement)
        target["diskon_produk"] = int(diskon_produk)
        target["diskon_tambahan_nilai"] = int(diskon_tambahan)
        target["add_disc"] = int(diskon_tambahan)
        target["kas_nilai"] = int(nilai_settlement)
        target["selisih_plus"] = int(max(0, selisih_settlement))
        return target
