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

"""Test API evaluations

Utilisation :
    créer les variables d'environnement: (indiquer les valeurs
    pour le serveur ScoDoc que vous voulez interroger)

    export SCODOC_URL="https://scodoc.xxx.net/"
    export SCODOC_USER="xxx"
    export SCODOC_PASSWD="xxx"
    export CHECK_CERTIFICATE=0 # ou 1 si serveur de production avec certif SSL valide

    (on peut aussi placer ces valeurs dans un fichier .env du répertoire tests/api).

    Lancer :
        pytest tests/api/test_api_evaluations.py
"""

import requests
from types import NoneType

from app.scodoc import sco_utils as scu
from tests.api.setup_test_api import (
    API_URL,
    CHECK_CERTIFICATE,
    GET,
    POST_JSON,
    api_admin_headers,
    api_headers,
    check_failure_post,
)
from tests.api.tools_test_api import (
    verify_fields,
    EVALUATIONS_FIELDS,
    NOTES_FIELDS,
)


def test_evaluations(api_headers):
    """
    Test 'evaluations'

    Route :
        - /moduleimpl/<int:moduleimpl_id>/evaluations
    """
    moduleimpl_id = 20
    r = requests.get(
        f"{API_URL}/moduleimpl/{moduleimpl_id}/evaluations",
        headers=api_headers,
        verify=CHECK_CERTIFICATE,
        timeout=scu.SCO_TEST_API_TIMEOUT,
    )
    assert r.status_code == 200
    evaluations = r.json()
    assert evaluations
    assert isinstance(evaluations, list)
    for e in evaluations:
        assert verify_fields(e, EVALUATIONS_FIELDS)
        assert isinstance(e["date_debut"], (str, NoneType))
        assert isinstance(e["date_fin"], (str, NoneType))
        assert isinstance(e["id"], int)
        assert isinstance(e["note_max"], float)
        assert isinstance(e["visibulletin"], bool)
        assert isinstance(e["evaluation_type"], int)
        assert isinstance(e["moduleimpl_id"], int)
        assert e["description"] is None or isinstance(e["description"], str)
        assert isinstance(e["coefficient"], float)
        assert isinstance(e["publish_incomplete"], bool)
        assert isinstance(e["numero"], int)
        assert isinstance(e["poids"], dict)

        assert e["moduleimpl_id"] == moduleimpl_id


def test_evaluation_notes(api_headers):
    """
    Test 'evaluation_notes'

    Route :
        - /evaluation/<int:evaluation_id>/notes
    """
    eval_id = 20
    r = requests.get(
        f"{API_URL}/evaluation/{eval_id}/notes",
        headers=api_headers,
        verify=CHECK_CERTIFICATE,
        timeout=scu.SCO_TEST_API_TIMEOUT,
    )
    assert r.status_code == 200
    eval_notes = r.json()
    assert eval_notes
    for etudid, note in eval_notes.items():
        assert int(etudid) == note["etudid"]
        assert verify_fields(note, NOTES_FIELDS)
        assert isinstance(note["etudid"], int)
        assert isinstance(note["evaluation_id"], int)
        assert isinstance(note["value"], float)
        assert isinstance(note["comment"], str)
        assert isinstance(note["date"], str)
        assert isinstance(note["uid"], int)

        assert eval_id == note["evaluation_id"]


def test_evaluation_create(api_admin_headers):
    """
    Test /moduleimpl/<int:moduleimpl_id>/evaluation/create
    """
    moduleimpl_id = 20
    # Nombre d'évaluations initial
    evaluations = GET(
        f"/moduleimpl/{moduleimpl_id}/evaluations", headers=api_admin_headers
    )
    nb_evals = len(evaluations)
    #
    e = POST_JSON(
        f"/moduleimpl/{moduleimpl_id}/evaluation/create",
        {"description": "eval test"},
        api_admin_headers,
    )
    assert isinstance(e, dict)
    assert verify_fields(e, EVALUATIONS_FIELDS)
    # Check default values
    assert e["note_max"] == 20.0
    assert e["evaluation_type"] == 0
    assert not e["date_debut"]
    assert not e["date_fin"]
    assert e["visibulletin"] is True
    assert e["publish_incomplete"] is False
    assert e["coefficient"] == 1.0
    new_nb_evals = len(
        GET(f"/moduleimpl/{moduleimpl_id}/evaluations", headers=api_admin_headers)
    )
    assert new_nb_evals == nb_evals + 1
    nb_evals = new_nb_evals

    # Avec une erreur
    check_failure_post(
        f"/moduleimpl/{moduleimpl_id}/evaluation/create",
        api_admin_headers,
        {"evaluation_type": 666},
        err="paramètre de type incorrect (invalid evaluation_type value)",
    )
    new_nb_evals = len(
        GET(f"/moduleimpl/{moduleimpl_id}/evaluations", headers=api_admin_headers)
    )
    assert new_nb_evals == nb_evals  # inchangé
    # Avec plein de valeurs
    data = {
        "coefficient": 12.0,
        "date_debut": "2021-10-15T08:30:00+02:00",
        "date_fin": "2021-10-15T10:30:00+02:00",
        "description": "eval test2",
        "evaluation_type": 1,
        "visibulletin": False,
        "publish_incomplete": True,
        "note_max": 100.0,
    }
    e = POST_JSON(
        f"/moduleimpl/{moduleimpl_id}/evaluation/create",
        data,
        api_admin_headers,
    )
    e_ret = GET(f"/evaluation/{e['id']}", headers=api_admin_headers)
    for k, v in data.items():
        assert e_ret[k] == v, f"received '{e_ret[k]}'"

    # Avec des poids APC
    nb_evals = len(
        GET(f"/moduleimpl/{moduleimpl_id}/evaluations", headers=api_admin_headers)
    )
    data.update(
        {
            "description": "eval test apc erreur",
            "poids": {"666": 666.0},  # poids erroné: UE inexistante
        }
    )
    check_failure_post(
        f"/moduleimpl/{moduleimpl_id}/evaluation/create",
        api_admin_headers,
        data,
    )
    new_nb_evals = len(
        GET(f"/moduleimpl/{moduleimpl_id}/evaluations", headers=api_admin_headers)
    )
    assert new_nb_evals == nb_evals  # inchangé
    # Avec des poids absurdes
    data.update({"description": "eval test apc erreur 2", "poids": "nimporte quoi"})
    check_failure_post(
        f"/moduleimpl/{moduleimpl_id}/evaluation/create",
        api_admin_headers,
        data,
    )
    new_nb_evals = len(
        GET(f"/moduleimpl/{moduleimpl_id}/evaluations", headers=api_admin_headers)
    )
    assert new_nb_evals == nb_evals  # inchangé
    # Avec de bons poids
    # pour cela il nous faut les UEs de ce formsemestre
    # sachant que l'on a moduleimpl
    modimpl = GET(f"/moduleimpl/{moduleimpl_id}", headers=api_admin_headers)
    formation = GET(
        f"/formsemestre/{modimpl['formsemestre_id']}/programme",
        headers=api_admin_headers,
    )
    ues = formation["ues"]
    assert len(ues)
    ue_ids = [ue["id"] for ue in ues]
    poids = {ue_id: float(i) + 0.5 for i, ue_id in enumerate(ue_ids)}
    data.update({"description": "eval avec poids", "poids": poids})
    e = POST_JSON(
        f"/moduleimpl/{moduleimpl_id}/evaluation/create",
        data,
        api_admin_headers,
    )
    assert e["poids"]
    e_ret = GET(f"/evaluation/{e['id']}", headers=api_admin_headers)
    assert e_ret["poids"] == e["poids"]
    new_nb_evals = len(
        GET(f"/moduleimpl/{moduleimpl_id}/evaluations", headers=api_admin_headers)
    )
    assert new_nb_evals == nb_evals + 1
    nb_evals = new_nb_evals
    # Delete
    ans = POST_JSON(
        f"/evaluation/{e_ret['id']}/delete",
        headers=api_admin_headers,
    )
    assert ans == "ok"
    assert nb_evals - 1 == len(
        GET(f"/moduleimpl/{moduleimpl_id}/evaluations", headers=api_admin_headers)
    )
