# edited by glg
import pytest

from pypos.modules.auth.services.login_attempt_guard_service import LoginAttemptGuardService
from pypos.modules.auth.services.offline_admin_auth_service import OfflineAdminAuthService


pytestmark = [pytest.mark.unit]


class _Clock:
    def __init__(self, start=1000.0):
        self._now = float(start)

    def __call__(self):
        return float(self._now)

    def add(self, seconds):
        self._now += float(seconds)


class _FakeModel:
    def __init__(self):
        self._row = {
            "id": 9,
            "nama": "Admin Toko",
            "password": "md5-dummy",
            "oto_settlement": 1,
        }
        self.updated = []

    def get_admin_offline_status(self, username):
        if str(username or "").strip().lower() == "admin":
            return dict(self._row)
        return None

    def update_password_hash_by_id(self, user_id, new_hash):
        self.updated.append((user_id, new_hash))


class _FakeAuthService:
    def verify_and_upgrade(self, password, _stored_hash):
        ok = str(password or "") == "rahasia"
        return ok, None


def _policy():
    return {
        "enabled": True,
        "login": {"max_attempts": 5, "window_seconds": 60, "lockout_seconds": 60},
        "offline_admin": {"max_attempts": 2, "window_seconds": 60, "lockout_seconds": 30},
        "master_password": {"max_attempts": 5, "window_seconds": 60, "lockout_seconds": 60},
    }


def test_offline_admin_guard_locks_after_repeated_failures():
    LoginAttemptGuardService._clear_all_for_test()
    clock = _Clock()
    guard = LoginAttemptGuardService(policy_getter=_policy, now_fn=clock)
    service = OfflineAdminAuthService(
        model=_FakeModel(),
        auth_service=_FakeAuthService(),
        attempt_guard_service=guard,
    )

    ok1, message1, _ = service.validate_admin_credentials("admin", "salah-1")
    ok2, message2, _ = service.validate_admin_credentials("admin", "salah-2")
    ok3, message3, _ = service.validate_admin_credentials("admin", "rahasia")

    assert ok1 is False
    assert "Password admin salah" in message1
    assert ok2 is False
    assert "Terlalu banyak percobaan" in message2
    assert ok3 is False
    assert "Terlalu banyak percobaan" in message3

    clock.add(31)
    ok4, message4, admin4 = service.validate_admin_credentials("admin", "rahasia")
    assert ok4 is True
    assert message4 == ""
    assert admin4["id"] == 9
