# edited by glg
import pytest

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


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)


def _policy(
    *,
    enabled=True,
    login_max=3,
    login_window=60,
    login_lock=30,
):
    return {
        "enabled": bool(enabled),
        "login": {
            "max_attempts": int(login_max),
            "window_seconds": int(login_window),
            "lockout_seconds": int(login_lock),
        },
        "offline_admin": {
            "max_attempts": 3,
            "window_seconds": 60,
            "lockout_seconds": 30,
        },
        "master_password": {
            "max_attempts": 3,
            "window_seconds": 60,
            "lockout_seconds": 30,
        },
    }


def test_login_attempt_guard_lock_and_expire():
    LoginAttemptGuardService._clear_all_for_test()
    clock = _Clock()
    service = LoginAttemptGuardService(
        policy_getter=lambda: _policy(),
        now_fn=clock,
    )

    first = service.record_failure(LoginAttemptGuardService.SCOPE_LOGIN, "kasir")
    second = service.record_failure(LoginAttemptGuardService.SCOPE_LOGIN, "kasir")
    third = service.record_failure(LoginAttemptGuardService.SCOPE_LOGIN, "kasir")

    assert first["locked"] is False
    assert second["locked"] is False
    assert third["locked"] is True
    assert third["remaining_seconds"] >= 1

    still_locked = service.check_attempt(LoginAttemptGuardService.SCOPE_LOGIN, "kasir")
    assert still_locked["locked"] is True

    clock.add(31)
    unlocked = service.check_attempt(LoginAttemptGuardService.SCOPE_LOGIN, "kasir")
    assert unlocked["locked"] is False


def test_login_attempt_guard_reset_clears_state():
    LoginAttemptGuardService._clear_all_for_test()
    service = LoginAttemptGuardService(policy_getter=lambda: _policy())
    service.record_failure(LoginAttemptGuardService.SCOPE_LOGIN, "kasir")
    service.reset_attempt(LoginAttemptGuardService.SCOPE_LOGIN, "kasir")
    status = service.check_attempt(LoginAttemptGuardService.SCOPE_LOGIN, "kasir")
    assert status["locked"] is False
    assert status["fail_count"] == 0


def test_login_attempt_guard_disabled_policy_never_locks():
    LoginAttemptGuardService._clear_all_for_test()
    service = LoginAttemptGuardService(policy_getter=lambda: _policy(enabled=False))
    for _ in range(10):
        state = service.record_failure(LoginAttemptGuardService.SCOPE_LOGIN, "kasir")
        assert state["locked"] is False
