class TransaksiRowIndexService:
    def __init__(self, parse_qty_callback):
        self._parse_qty = parse_qty_callback
        self._row_index_map = {}

    def clear(self):
        self._row_index_map.clear()

    def register(self, produk_id, row_index):
        pid = str(produk_id or "").strip()
        if not pid:
            return
        try:
            self._row_index_map[pid] = int(row_index)
        except (TypeError, ValueError, OverflowError):
            return

    def rebuild(self, table, id_column=0):
        self.clear()
        if table is None:
            return
        for row in range(table.rowCount()):
            item = table.item(row, id_column)
            if not item:
                continue
            pid = str(item.text() or "").strip()
            if pid:
                self._row_index_map[pid] = row

    def shift_after_remove(self, removed_row, removed_produk_id=None):
        try:
            removed_idx = int(removed_row)
        except (TypeError, ValueError, OverflowError):
            return
        pid = str(removed_produk_id or "").strip()
        if pid:
            self._row_index_map.pop(pid, None)
        else:
            for key, idx in list(self._row_index_map.items()):
                if idx == removed_idx:
                    self._row_index_map.pop(key, None)
                    break
        for key, idx in list(self._row_index_map.items()):
            if idx > removed_idx:
                self._row_index_map[key] = idx - 1

    def find_row(self, table, produk_id, id_column=0, qty_column=4):
        pid = str(produk_id or "").strip()
        if not pid:
            return None, 0
        mapped_row = self._row_index_map.get(pid)
        if mapped_row is not None:
            if 0 <= mapped_row < table.rowCount():
                mapped_item = table.item(mapped_row, id_column)
                if mapped_item and mapped_item.text() == pid:
                    qty_item = table.item(mapped_row, qty_column)
                    qty = self._parse_qty(qty_item.text()) if qty_item else 0
                    return mapped_row, qty
            self._row_index_map.pop(pid, None)
        for row in range(table.rowCount()):
            item = table.item(row, id_column)
            if item and item.text() == pid:
                self.register(pid, row)
                qty_item = table.item(row, qty_column)
                qty = self._parse_qty(qty_item.text()) if qty_item else 0
                return row, qty
        return None, 0
