# edited by glg
import sqlite3
import tempfile
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from unittest.mock import patch

from pypos.modules.penjualan.services.transaksi_counter_service import TransaksiCounterService


def _read_counter(db_path, nama):
    conn = sqlite3.connect(db_path)
    cur = conn.cursor()
    cur.execute("SELECT counter FROM penomoran WHERE nama = ?", (nama,))
    row = cur.fetchone()
    conn.close()
    return int((row[0] if row else 0) or 0)


def test_get_and_increment_counter_sequential():
    with tempfile.TemporaryDirectory(ignore_cleanup_errors=True) as td:
        db_path = str(Path(td) / "counter_seq.db")
        svc = TransaksiCounterService(db_path=db_path)
        assert svc.get_and_increment_counter("transaksi") == 1
        assert svc.get_and_increment_counter("transaksi") == 2
        assert _read_counter(db_path, "transaksi") == 2


def test_get_and_increment_counter_parallel_atomic():
    with tempfile.TemporaryDirectory(ignore_cleanup_errors=True) as td:
        db_path = str(Path(td) / "counter_parallel.db")
        svc = TransaksiCounterService(db_path=db_path)
        total_call = 40

        def _call_once(_):
            return svc.get_and_increment_counter("trx_parallel")

        with ThreadPoolExecutor(max_workers=8) as pool:
            results = list(pool.map(_call_once, range(total_call)))

        assert len(results) == total_call
        assert len(set(results)) == total_call
        assert sorted(results) == list(range(1, total_call + 1))
        assert _read_counter(db_path, "trx_parallel") == total_call


def test_get_and_increment_counter_retry_saat_lock_contention():
    with tempfile.TemporaryDirectory(ignore_cleanup_errors=True) as td:
        db_path = str(Path(td) / "counter_retry.db")
        svc = TransaksiCounterService(db_path=db_path)
        original_impl = svc._increment_counter_atomic
        attempts = {"count": 0}

        def flaky_once(cursor, normalized_name):
            attempts["count"] += 1
            if attempts["count"] == 1:
                raise sqlite3.OperationalError("database is locked")
            return original_impl(cursor, normalized_name)

        with patch.object(svc, "_increment_counter_atomic", side_effect=flaky_once):
            value = svc.get_and_increment_counter("trx_retry")

        assert value == 1
        assert attempts["count"] >= 2
