# tests/test_operator_users.py
import uuid
from tests.conftest import wire_operator_auth
from backend.operator_auth import create_operator, make_operator_cookie, COOKIE_NAME
from backend.models import OperatorUser


def _login_as(client, user):
    client.cookies.set(COOKIE_NAME, make_operator_cookie(user.id))


def test_admin_cannot_reach_user_management(client, db_session, monkeypatch):
    admin, _ = create_operator(db_session, "admin@x.com", "Admin", "admin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, admin)
    assert client.get("/admin/users", follow_redirects=False).status_code == 403


def test_superadmin_sees_user_management(client, db_session, monkeypatch):
    su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, su)
    assert client.get("/admin/users", follow_redirects=False).status_code == 200


def test_superadmin_lists_users_json(client, db_session, monkeypatch):
    su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, su)
    r = client.get("/api/admin/users")
    assert r.status_code == 200
    emails = [u["email"] for u in r.json()["users"]]
    assert "su@x.com" in emails
    assert all("password_hash" not in u for u in r.json()["users"])  # never leak hashes


def test_create_user_returns_temp_once(client, db_session, monkeypatch):
    su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, su)
    r = client.post("/api/admin/users",
                    json={"email": "dad@x.com", "name": "Dad", "role": "admin"})
    assert r.status_code == 200
    assert len(r.json()["password"]) >= 12
    made = db_session.query(OperatorUser).filter_by(email="dad@x.com").first()
    assert made.must_change_password is True


def test_reset_password_returns_temp_once(client, db_session, monkeypatch):
    su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
    target, _ = create_operator(db_session, "t@x.com", "T", "admin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, su)
    r = client.post(f"/api/admin/users/{target.id}/reset-password")
    assert r.status_code == 200 and len(r.json()["password"]) >= 12
    db_session.refresh(target)
    assert target.must_change_password is True


def test_disable_and_enable(client, db_session, monkeypatch):
    su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
    target, _ = create_operator(db_session, "t@x.com", "T", "admin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, su)
    assert client.post(f"/api/admin/users/{target.id}/disable").status_code == 200
    db_session.refresh(target); assert target.active is False
    assert client.post(f"/api/admin/users/{target.id}/enable").status_code == 200
    db_session.refresh(target); assert target.active is True


def test_change_role(client, db_session, monkeypatch):
    su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
    target, _ = create_operator(db_session, "t@x.com", "T", "admin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, su)
    r = client.post(f"/api/admin/users/{target.id}/role", json={"role": "superadmin"})
    assert r.status_code == 200
    db_session.refresh(target); assert target.role == "superadmin"


def test_admin_cannot_reach_json_endpoints(client, db_session, monkeypatch):
    admin, _ = create_operator(db_session, "a@x.com", "A", "admin", password="pw-123456")
    target, _ = create_operator(db_session, "t@x.com", "T", "admin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, admin)
    assert client.get("/api/admin/users").status_code == 403
    assert client.post("/api/admin/users", json={"email": "x@x.com", "name": "X", "role": "admin"}).status_code == 403
    assert client.post(f"/api/admin/users/{target.id}/reset-password").status_code == 403
    assert client.post(f"/api/admin/users/{target.id}/disable").status_code == 403
    assert client.post(f"/api/admin/users/{target.id}/enable").status_code == 403
    assert client.post(f"/api/admin/users/{target.id}/role", json={"role": "superadmin"}).status_code == 403


def test_cannot_disable_own_account(client, db_session, monkeypatch):
    su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, su)
    r = client.post(f"/api/admin/users/{su.id}/disable")
    assert r.status_code == 400
    db_session.refresh(su)
    assert su.active is True


def test_cannot_change_own_role(client, db_session, monkeypatch):
    su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, su)
    r = client.post(f"/api/admin/users/{su.id}/role", json={"role": "admin"})
    assert r.status_code == 400
    db_session.refresh(su)
    assert su.role == "superadmin"


def test_deferred_operator_role_rejected_by_api(client, db_session, monkeypatch):
    su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
    target, _ = create_operator(db_session, "t@x.com", "T", "admin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=True)
    _login_as(client, su)
    assert client.post("/api/admin/users", json={"email": "op@x.com", "name": "Op", "role": "operator"}).status_code == 400
    assert client.post(f"/api/admin/users/{target.id}/role", json={"role": "operator"}).status_code == 400


def test_admin_surface_404s_when_flag_off(client, db_session, monkeypatch):
    su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456")
    wire_operator_auth(monkeypatch, db_session, enabled=False)
    _login_as(client, su)
    # With operator auth OFF, the management surface must not exist (404), even
    # though require_role passes through — otherwise it'd be world-open.
    assert client.get("/admin/users").status_code == 404
    assert client.get("/api/admin/users").status_code == 404
    assert client.post("/api/admin/users",
                       json={"email": "x@x.com", "name": "X", "role": "admin"}).status_code == 404
