# retoor <retoor@molodetz.nl>

import time
import pytest
import requests
from tests.conftest import BASE_URL
from devplacepy.database import get_table, refresh_snapshot, set_setting

JSON = {"Accept": "application/json"}
_counter = [0]


@pytest.fixture(scope="module", autouse=True)
def _settings(app_server):
    for key, value in {
        "rate_limit_per_minute": "1000000",
        "rate_limit_window_seconds": "60",
        "registration_open": "1",
        "maintenance_mode": "0",
        "session_max_age_days": "7",
        "session_remember_days": "30",
    }.items():
        set_setting(key, value)
    yield


def _db_user(name):
    refresh_snapshot()
    return get_table("users").find_one(username=name)


def _unique(prefix="sen"):
    _counter[0] += 1
    return f"{prefix}{int(time.time() * 1000)}{_counter[0]}"


def _signup():
    name = _unique("senmem")
    s = requests.Session()
    s.post(
        f"{BASE_URL}/auth/signup",
        data={
            "username": name,
            "email": f"{name}@t.dev",
            "password": "secret123",
            "confirm_password": "secret123",
            "birth_date": "1990-01-01",
            "accept_terms": "1",
        },
        allow_redirects=True,
    )
    return name


def _key_session(name):
    s = requests.Session()
    s.headers.update({"X-API-KEY": _db_user(name)["api_key"]})
    return s


def _alice():
    return _key_session("alice_test")


def _promote(actor, uid):
    actor.post(
        f"{BASE_URL}/admin/users/{uid}/role",
        headers=JSON,
        data={"role": "admin"},
        allow_redirects=False,
    )


def _audit(session, **params):
    r = session.get(f"{BASE_URL}/admin/audit-log", headers=JSON, params=params)
    assert r.status_code == 200, r.text[:300]
    return r.json()["entries"]


def _denied(session, event_key, target_uid):
    for e in _audit(session, event_key=event_key, result="denied"):
        if e.get("target_uid") == target_uid:
            return e
    return None


def _junior_admin(seeded_db):
    alice = _alice()
    name = _signup()
    uid = _db_user(name)["uid"]
    _promote(alice, uid)
    assert _db_user(name)["role"] == "Admin"
    return _key_session(name), name, uid


def test_junior_admin_cannot_change_senior_admin_role(seeded_db):
    junior, _, _ = _junior_admin(seeded_db)
    alice_uid = _db_user("alice_test")["uid"]
    junior.post(
        f"{BASE_URL}/admin/users/{alice_uid}/role",
        headers=JSON,
        data={"role": "member"},
        allow_redirects=False,
    )
    assert _denied(_alice(), "admin.user.role.change", alice_uid) is not None
    assert _db_user("alice_test")["role"] == "Admin"


def test_junior_admin_cannot_disable_senior_admin(seeded_db):
    junior, _, _ = _junior_admin(seeded_db)
    alice_uid = _db_user("alice_test")["uid"]
    junior.post(
        f"{BASE_URL}/admin/users/{alice_uid}/toggle",
        headers=JSON,
        allow_redirects=False,
    )
    assert _denied(_alice(), "admin.user.active.disable", alice_uid) is not None
    assert _db_user("alice_test").get("is_active", True)


def test_junior_admin_cannot_reset_senior_admin_password(seeded_db):
    junior, _, _ = _junior_admin(seeded_db)
    alice_uid = _db_user("alice_test")["uid"]
    before = _db_user("alice_test")["password_hash"]
    junior.post(
        f"{BASE_URL}/admin/users/{alice_uid}/password",
        headers=JSON,
        data={"password": "hijacked999"},
        allow_redirects=False,
    )
    assert _denied(_alice(), "admin.user.password.reset", alice_uid) is not None
    assert _db_user("alice_test")["password_hash"] == before


def test_junior_admin_cannot_reset_senior_admin_quota(seeded_db):
    junior, _, _ = _junior_admin(seeded_db)
    alice_uid = _db_user("alice_test")["uid"]
    junior.post(
        f"{BASE_URL}/admin/users/{alice_uid}/reset-ai-quota",
        headers=JSON,
        allow_redirects=False,
    )
    assert _denied(_alice(), "admin.user.ai_quota.reset", alice_uid) is not None


def test_senior_admin_can_disable_junior_admin(seeded_db):
    _junior, _, junior_uid = _junior_admin(seeded_db)
    alice = _alice()
    alice.post(
        f"{BASE_URL}/admin/users/{junior_uid}/toggle",
        headers=JSON,
        allow_redirects=False,
    )
    refresh_snapshot()
    assert not get_table("users").find_one(uid=junior_uid).get("is_active", True)


def test_junior_admin_can_manage_member(seeded_db):
    junior, _, _ = _junior_admin(seeded_db)
    member = _signup()
    member_uid = _db_user(member)["uid"]
    junior.post(
        f"{BASE_URL}/admin/users/{member_uid}/toggle",
        headers=JSON,
        allow_redirects=False,
    )
    refresh_snapshot()
    assert not get_table("users").find_one(uid=member_uid).get("is_active", True)
