import datetime as dt

import pytest

from flyway.auth.service import (
    authenticate, change_password, create_session, create_user, delete_session, load_session,
)
from flyway.domain.errors import BusinessError

NOW = dt.datetime(2026, 5, 1, tzinfo=dt.UTC)


def test_password_min_length(db):
    with pytest.raises(BusinessError):
        create_user(db, "amy", "short")


def test_authenticate_case_insensitive_username(db):
    create_user(db, "Amy", "secret-pw", first_name="Amy", last_name="Lee")
    user = authenticate(db, "amy", "secret-pw", NOW)
    assert user.full_name == "Amy Lee" and user.last_login_at == NOW


def test_five_failures_in_ten_minutes_lock_account(db):
    create_user(db, "amy", "secret-pw")
    for n in range(5):
        with pytest.raises(BusinessError):
            authenticate(db, "amy", "wrong", NOW + dt.timedelta(minutes=n))
    with pytest.raises(BusinessError):
        authenticate(db, "amy", "secret-pw", NOW + dt.timedelta(minutes=6))


def test_failures_outside_window_reset_counter(db):
    create_user(db, "amy", "secret-pw")
    for n in range(4):
        with pytest.raises(BusinessError):
            authenticate(db, "amy", "wrong", NOW)
    with pytest.raises(BusinessError):
        authenticate(db, "amy", "wrong", NOW + dt.timedelta(minutes=11))
    assert authenticate(db, "amy", "secret-pw", NOW + dt.timedelta(minutes=12)).failed_attempts == 0


def test_session_roundtrip_and_expiry(db):
    user = create_user(db, "amy", "secret-pw")
    token, csrf = create_session(db, user, NOW)
    assert load_session(db, token, NOW).csrf_token == csrf
    assert load_session(db, token, NOW + dt.timedelta(hours=49)) is None
    delete_session(db, token)
    assert load_session(db, token, NOW) is None


def test_change_password_checks_current(db):
    user = create_user(db, "amy", "secret-pw")
    with pytest.raises(BusinessError):
        change_password(db, user, "nope", "new-secret")
    change_password(db, user, "secret-pw", "new-secret")
    assert authenticate(db, "amy", "new-secret", NOW)
