# -*- coding: utf-8 -*-

"""Test API : utilisateurs

Utilisation :
    pytest tests/api/test_api_users.py
"""

from tests.api.setup_test_api import (
    API_URL,
    APIError,
    CHECK_CERTIFICATE,
    GET,
    POST_JSON,
    api_headers,
    api_admin_headers,
    get_auth_headers,
)


def test_list_users(api_admin_headers):
    """
    Routes: /user/<int:uid>
            /users/query?departement=dept_acronym&active=1&like=<str:nom>
    """
    admin_h = api_admin_headers
    depts = GET("/departements", headers=admin_h)
    assert len(depts) > 0
    u = GET("/user/1", headers=admin_h)
    assert u["id"] == 1
    assert u["user_name"]
    assert u["date_expiration"] is None
    dept_u = u["dept"]

    # Tous les utilisateurs, vus par SuperAdmin:
    users = GET("/users/query", headers=admin_h)
    assert len(users) > 2
    # Les utilisateurs du dept. TAPI
    users_TAPI = GET("/users/query?departement=TAPI", headers=admin_h)
    nb_TAPI = len(users_TAPI)
    assert nb_TAPI > 1
    # Les utilisateurs de chaque département (+ ceux sans département)
    all_users = []
    for acronym in [dept["acronym"] for dept in depts] + [""]:
        all_users += GET(f"/users/query?departement={acronym}", headers=admin_h)
    all_users.sort(key=lambda u: u["user_name"])
    assert len(all_users) == len(users)
    # On a créé un user "u_" par département:
    u_users = GET("/users/query?starts_with=U ", headers=admin_h)
    assert len(u_users) == len(depts)
    assert len(GET("/users/query?departement=AA", headers=admin_h)) == 1
    assert len(GET("/users/query?departement=AA&starts_with=U ", headers=admin_h)) == 1
    assert (
        len(
            GET(
                "/users/query?departement=AA&starts_with=XXX",
                headers=admin_h,
            )
        )
        == 0
    )
    # Utilisateurs vus par d'autres utilisateurs (droits accès)
    for i, u in enumerate(u for u in u_users if u["dept"] != "TAPI"):
        headers = get_auth_headers(u["user_name"], "test")
        users_by_u = GET("/users/query", headers=headers)
        assert len(users_by_u) == nb_TAPI + 1 + i
        # explication: tous ont le droit de voir les users de TAPI
        # plus l'utilisateur de chaque département jusqu'au leur
        # (u_AA voit AA, u_BB voit AA et BB, etc)


def test_edit_users(api_admin_headers):
    """
    Routes: /user/create
            /user/edit/<int:uid>
    """
    admin_h = api_admin_headers
    nb_users = len(GET("/users/query", headers=admin_h))
    user = POST_JSON(
        "/user/create",
        {"user_name": "test_edit_users", "nom": "Toto"},
        headers=admin_h,
    )
    assert user["user_name"] == "test_edit_users"
    assert user["dept"] is None
    assert user["active"] is True
    assert (nb_users + 1) == len(GET("/users/query", headers=admin_h))
    # Change le dept et rend inactif
    user = POST_JSON(
        f"/user/{user['id']}/edit",
        {"active": False, "dept": "TAPI"},
        headers=admin_h,
    )
    assert user["dept"] == "TAPI"
    assert user["active"] is False
    user = GET(f"/user/{user['id']}", headers=admin_h)
    assert user["nom"] == "Toto"
    assert user["dept"] == "TAPI"
    assert user["active"] is False


def test_roles(api_admin_headers):
    """
    Routes: /user/create
            /user/<int:uid>/edit
    """
    admin_h = api_admin_headers
    user = POST_JSON(
        "/user/create",
        {"user_name": "test_roles", "nom": "Role", "prenom": "Test"},
        headers=admin_h,
    )
    uid = user["id"]
    ans = POST_JSON(f"/user/{uid}/role/Secr/add", headers=admin_h)
    assert ans["user_name"] == "test_roles"
    role = POST_JSON("/role/create/Test_X", headers=admin_h)
    assert role["role_name"] == "Test_X"
    assert role["permissions"] == []
    role = GET("/role/Test_X", headers=admin_h)
    assert role["role_name"] == "Test_X"
    assert role["permissions"] == []
    role = POST_JSON("/role/Test_X/edit", {"role_name": "Test_Y"}, headers=admin_h)
    assert role["role_name"] == "Test_Y"
    role = GET("/role/Test_Y", headers=admin_h)
    assert role["role_name"] == "Test_Y"
    role = POST_JSON(
        "/role/Test_Y/edit",
        {"permissions": ["ScoView", "ScoAbsChange"]},
        headers=admin_h,
    )
    assert set(role["permissions"]) == {"ScoView", "ScoAbsChange"}
    role = POST_JSON("/role/Test_Y/add_permission/ScoAbsAddBillet", headers=admin_h)
    assert set(role["permissions"]) == {"ScoView", "ScoAbsChange", "ScoAbsAddBillet"}
    role = GET("/role/Test_Y", headers=admin_h)
    assert set(role["permissions"]) == {"ScoView", "ScoAbsChange", "ScoAbsAddBillet"}
    role = POST_JSON("/role/Test_Y/remove_permission/ScoAbsChange", headers=admin_h)
    assert set(role["permissions"]) == {"ScoView", "ScoAbsAddBillet"}
    ans = POST_JSON("/role/Test_Y/delete", headers=admin_h)
    assert ans["OK"] is True


def test_modif_users_depts(api_admin_headers):
    """
    Ce test vise à vérifier qu'un admin déclaré sur deux départements peut
    bien modifier les utilisateurs de ses départements mais pas ceux des autres.
    """
    admin_h = api_admin_headers
    depts = GET("/departements", headers=admin_h)
    assert len(depts) > 2
    dept1, dept2, dept3 = depts[:3]
    # On va utiliser les 3 1er dept (TAPI, AA, BB)
    # On crée un nouvel utilisateur "chef2", admin dans les 2 premiers dept
    # puis un utilisateur lambda, dans le dept 2 (AA)
    chef2 = POST_JSON(
        "/user/create",
        {
            "user_name": "chef2",
            "nom": "Chef",
            "prenom": "Test",
            "dept": dept1["acronym"],  # rattaché à dept1
        },
        headers=admin_h,
    )
    role_chef = POST_JSON(
        "/role/create/chef",
        {"permissions": ["ScoView", "ScoUsersAdmin", "ScoUsersView"]},
        headers=admin_h,
    )
    _ = POST_JSON(
        f"/user/{chef2['id']}/role/chef/add/departement/{dept1['acronym']}",
        headers=admin_h,
    )
    _ = POST_JSON(
        f"/user/{chef2['id']}/role/chef/add/departement/{dept2['acronym']}",
        headers=admin_h,
    )
    # Un mot de passe trop simple:
    ok = False
    try:
        _ = POST_JSON(
            f"/user/{chef2['id']}/password",
            {"password": "123456"},
            headers=admin_h,
        )
    except APIError as exc:
        if exc.args[1]["status"] == 400:
            ok = True
    assert ok
    # Un "vrai" mot de passe:
    chef2_password = "17HIOPpYhabb8qw'E:/jd7FFddjd"
    _ = POST_JSON(
        f"/user/{chef2['id']}/password",
        {"password": chef2_password},
        headers=admin_h,
    )
    # Création user lambda:
    u_lambda = POST_JSON(
        "/user/create",
        {
            "user_name": "lambda",
            "nom": "Lambda",
            "prenom": "Test",
            "dept": dept2["acronym"],
        },
        headers=admin_h,
    )

    # Le chef va modifier u_lambda:
    chef_h = get_auth_headers(chef2["user_name"], chef2_password)
    # on utilise une URL avec département car on n'a pas le droit sur tous:
    u = POST_JSON(
        f"/user/{u_lambda['id']}/edit",
        {"nom": "toto"},
        headers=chef_h,
        dept=dept1["acronym"],
    )
    assert u["nom"] == "toto"
    # Dans l'autre ?
    u = POST_JSON(
        f"/user/{u_lambda['id']}/edit",
        {"nom": "toto"},
        headers=chef_h,
        dept=dept2["acronym"],
    )
    # mais pas dans le troisième:
    ok = False
    try:
        u = POST_JSON(
            f"/user/{u_lambda['id']}/edit",
            {"nom": "toto"},
            headers=chef_h,
            dept=dept3["acronym"],
        )
    except APIError as exc:
        if exc.args[1]["status"] == 401:
            ok = True
    assert ok
    # Nettoyage:
    # on ne peut pas supprimer l'utilisateur lambda, mais on
    # le rend inactif et on le retire de son département
    u = POST_JSON(
        f"/user/{u_lambda['id']}/edit",
        {"active": False, "dept": None},
        headers=admin_h,
    )