# -*- mode: python -*-
# -*- coding: utf-8 -*-

##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2022 Emmanuel Viennet.  All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#   Emmanuel Viennet      emmanuel.viennet@viennet.net
#
##############################################################################

"""Recherche d'étudiants
"""
import flask
from flask import url_for, g, request
from flask_login import current_user

import app
from app.models import Departement
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header
from app.scodoc import sco_etud
from app.scodoc import sco_groups
from app.scodoc.sco_exceptions import ScoException
from app.scodoc.sco_permissions import Permission
from app.scodoc import sco_preferences


def form_search_etud(
    dest_url=None,
    parameters=None,
    parameters_keys=None,
    title="Rechercher un étudiant par nom : ",
    add_headers=False,  # complete page
):
    "form recherche par nom"
    H = []
    H.append(
        f"""<form action="{ url_for("scolar.search_etud_in_dept", scodoc_dept=g.scodoc_dept) }" method="POST">
    <b>{title}</b>
    <input type="text" name="expnom" class="in-expnom" width="12" spellcheck="false" value="">
    <input type="submit" value="Chercher">
    <br/>(entrer une partie du nom)
    """
    )
    if dest_url:
        H.append('<input type="hidden" name="dest_url" value="%s"/>' % dest_url)
    if parameters:
        for param in parameters.keys():
            H.append(
                '<input type="hidden" name="%s" value="%s"/>'
                % (param, parameters[param])
            )
        H.append(
            '<input type="hidden" name="parameters_keys" value="%s"/>'
            % (",".join(parameters.keys()))
        )
    elif parameters_keys:
        if request.method == "POST":
            vals = request.form
        elif request.method == "GET":
            vals = request.args
        else:
            vals = {}
        for key in parameters_keys.split(","):
            v = vals.get(key, False)
            if v:
                H.append('<input type="hidden" name="%s" value="%s"/>' % (key, v))
        H.append(
            '<input type="hidden" name="parameters_keys" value="%s"/>' % parameters_keys
        )
    H.append("</form>")

    if add_headers:
        return (
            html_sco_header.sco_header(page_title="Choix d'un étudiant")
            + "\n".join(H)
            + html_sco_header.sco_footer()
        )
    else:
        return "\n".join(H)


def search_etud_in_dept(expnom=""):
    """Page recherche d'un etudiant.

    Affiche la fiche de l'étudiant, ou, si la recherche donne plusieurs résultats,
    la liste des étudiants correspondants.
    Appelée par:
    - boite de recherche barre latérale gauche.
    - choix d'un étudiant à inscrire (en POST avec dest_url  et parameters_keys)

    Args:
        expnom: string, regexp sur le nom ou un code_nip ou un etudid
    """
    if isinstance(expnom, int) or len(expnom) > 1:
        try:
            etudid = int(expnom)
        except ValueError:
            etudid = None
        if etudid is not None:
            etuds = sco_etud.get_etud_info(filled=True, etudid=expnom)
        if (etudid is None) or len(etuds) != 1:
            expnom_str = str(expnom)
            if scu.is_valid_code_nip(expnom_str):
                etuds = search_etuds_infos(code_nip=expnom_str)
            else:
                etuds = search_etuds_infos(expnom=expnom_str)
    else:
        etuds = []  # si expnom est trop court, n'affiche rien

    if request.method == "POST":
        vals = request.form
    elif request.method == "GET":
        vals = request.args
    else:
        vals = {}

    url_args = {"scodoc_dept": g.scodoc_dept}
    if "dest_url" in vals:
        endpoint = vals["dest_url"]
    else:
        endpoint = "scolar.ficheEtud"
    if "parameters_keys" in vals:
        for key in vals["parameters_keys"].split(","):
            url_args[key] = vals[key]

    if len(etuds) == 1:
        # va directement a la fiche
        url_args["etudid"] = etuds[0]["etudid"]
        return flask.redirect(url_for(endpoint, **url_args))

    H = [
        html_sco_header.sco_header(
            page_title="Recherche d'un étudiant",
            no_side_bar=False,
            init_qtip=True,
            javascripts=["js/etud_info.js"],
        )
    ]
    if len(etuds) == 0 and len(etuds) <= 1:
        H.append("""<h2>chercher un étudiant:</h2>""")
    else:
        H.append(
            f"""<h2>{len(etuds)} résultats pour "<tt>{expnom}</tt>": choisissez un étudiant:</h2>"""
        )
    H.append(
        form_search_etud(
            dest_url=endpoint,
            parameters=vals.get("parameters"),
            parameters_keys=vals.get("parameters_keys"),
            title="Autre recherche",
        )
    )
    if len(etuds) > 0:
        # Choix dans la liste des résultats:
        for e in etuds:
            url_args["etudid"] = e["etudid"]
            target = url_for(endpoint, **url_args)
            e["_nomprenom_target"] = target
            e["inscription_target"] = target
            e["_nomprenom_td_attrs"] = 'id="%s" class="etudinfo"' % (e["etudid"])
            sco_groups.etud_add_group_infos(
                e, e["cursem"]["formsemestre_id"] if e["cursem"] else None
            )

        tab = GenTable(
            columns_ids=("nomprenom", "code_nip", "inscription", "groupes"),
            titles={
                "nomprenom": "Etudiant",
                "code_nip": "NIP",
                "inscription": "Inscription",
                "groupes": "Groupes",
            },
            rows=etuds,
            html_sortable=True,
            html_class="table_leftalign",
            preferences=sco_preferences.SemPreferences(),
        )
        H.append(tab.html())
        if len(etuds) > 20:  # si la page est grande
            H.append(
                form_search_etud(
                    dest_url=endpoint,
                    parameters=vals.get("parameters"),
                    parameters_keys=vals.get("parameters_keys"),
                    title="Autre recherche",
                )
            )
    else:
        H.append('<h2 style="color: red;">Aucun résultat pour "%s".</h2>' % expnom)
    H.append(
        """<p class="help">La recherche porte sur tout ou partie du NOM ou du NIP de l'étudiant. Saisir au moins deux caractères.</p>"""
    )
    return "\n".join(H) + html_sco_header.sco_footer()


# Was chercheEtudsInfo()
def search_etuds_infos(expnom=None, code_nip=None):
    """recherche les étudiants correspondants à expnom ou au code_nip
    et ramene liste de mappings utilisables en DTML.
    """
    may_be_nip = scu.is_valid_code_nip(expnom)
    cnx = ndb.GetDBConnexion()
    if expnom and not may_be_nip:
        expnom = expnom.upper()  # les noms dans la BD sont en uppercase
        try:
            etuds = sco_etud.etudident_list(cnx, args={"nom": expnom}, test="~")
        except ScoException:
            etuds = []
    else:
        code_nip = code_nip or expnom
        if code_nip:
            etuds = sco_etud.etudident_list(cnx, args={"code_nip": str(code_nip)})
        else:
            etuds = []
    sco_etud.fill_etuds_info(etuds)
    return etuds


def search_etud_by_name(term: str) -> list:
    """Recherche noms étudiants par début du nom, pour autocomplete
    Accepte aussi un début de code NIP (au moins 6 caractères)
    Renvoie une liste de dicts
         { "label" : "<nip> <nom> <prenom>", "value" : etudid }
    """
    may_be_nip = scu.is_valid_code_nip(term)
    # term = term.upper() # conserve les accents
    term = term.upper()
    if (
        not scu.ALPHANUM_EXP.match(term)  #  n'autorise pas les caractères spéciaux
        and not may_be_nip
    ):
        data = []
    else:
        if may_be_nip:
            r = ndb.SimpleDictFetch(
                """SELECT nom, prenom, code_nip
                FROM identite
                WHERE
                dept_id = %(dept_id)s 
                AND code_nip LIKE %(beginning)s 
                ORDER BY nom
                """,
                {"beginning": term + "%", "dept_id": g.scodoc_dept_id},
            )
            data = [
                {
                    "label": "%s %s %s"
                    % (x["code_nip"], x["nom"], sco_etud.format_prenom(x["prenom"])),
                    "value": x["code_nip"],
                }
                for x in r
            ]
        else:
            r = ndb.SimpleDictFetch(
                """SELECT id AS etudid, nom, prenom
                FROM identite
                WHERE 
                dept_id = %(dept_id)s 
                AND nom LIKE %(beginning)s
                ORDER BY nom
                """,
                {"beginning": term + "%", "dept_id": g.scodoc_dept_id},
            )

            data = [
                {
                    "label": "%s %s" % (x["nom"], sco_etud.format_prenom(x["prenom"])),
                    "value": x["etudid"],
                }
                for x in r
            ]
    return data


# ---------- Recherche sur plusieurs département


def search_etud_in_accessible_depts(expnom=None, code_nip=None):
    """
    result is a list of (sorted) etuds, one list per dept.
    """
    result = []
    accessible_depts = []
    depts = Departement.query.filter_by(visible=True).all()
    for dept in depts:
        if current_user.has_permission(Permission.ScoView, dept=dept.acronym):
            if expnom or code_nip:
                accessible_depts.append(dept.acronym)
                app.set_sco_dept(dept.acronym)
                etuds = search_etuds_infos(expnom=expnom, code_nip=code_nip)
            else:
                etuds = []
            result.append(etuds)
    return result, accessible_depts


def table_etud_in_accessible_depts(expnom=None):
    """
    Page avec table étudiants trouvés, dans tous les departements.
    Attention: nous sommes ici au niveau de ScoDoc, pas dans un département
    """
    result, accessible_depts = search_etud_in_accessible_depts(expnom=expnom)
    H = [
        """<div class="table_etud_in_accessible_depts">""",
        """<h3>Recherche multi-département de "<tt>%s</tt>"</h3>""" % expnom,
    ]
    for etuds in result:
        if etuds:
            dept_id = etuds[0]["dept"]
            # H.append('<h3>Département %s</h3>' % DeptId)
            for e in etuds:
                e["_nomprenom_target"] = url_for(
                    "scolar.ficheEtud", scodoc_dept=dept_id, etudid=e["etudid"]
                )
                e["_nomprenom_td_attrs"] = 'id="%s" class="etudinfo"' % (e["etudid"])

            tab = GenTable(
                titles={"nomprenom": "Etudiants en " + dept_id},
                columns_ids=("nomprenom",),
                rows=etuds,
                html_sortable=True,
                html_class="table_leftalign",
            )

            H.append('<div class="table_etud_in_dept">')
            H.append(tab.html())
            H.append("</div>")
    if len(accessible_depts) > 1:
        ss = "s"
    else:
        ss = ""
    H.append(
        f"""<p>(recherche menée dans le{ss} département{ss}: 
        {", ".join(accessible_depts)})
        </p>
        <p>
            <a href="{url_for("scodoc.index")}" class="stdlink">Retour à l'accueil</a>
        </p>
        </div>
        """
    )
    return (
        html_sco_header.scodoc_top_html_header(page_title="Choix d'un étudiant")
        + "\n".join(H)
        + html_sco_header.standard_html_footer()
    )


def search_inscr_etud_by_nip(code_nip, format="json"):
    """Recherche multi-departement d'un étudiant par son code NIP
    Seuls les départements accessibles par l'utilisateur sont cherchés.

    Renvoie une liste des inscriptions de l'étudiants dans tout ScoDoc:
    code_nip, nom, prenom, civilite_str, dept, formsemestre_id, date_debut_sem, date_fin_sem
    """
    result, _ = search_etud_in_accessible_depts(code_nip=code_nip)

    T = []
    for etuds in result:
        if etuds:
            DeptId = etuds[0]["dept"]
            for e in etuds:
                for sem in e["sems"]:
                    T.append(
                        {
                            "dept": DeptId,
                            "etudid": e["etudid"],
                            "code_nip": e["code_nip"],
                            "civilite_str": e["civilite_str"],
                            "nom": e["nom"],
                            "prenom": e["prenom"],
                            "formsemestre_id": sem["formsemestre_id"],
                            "date_debut_iso": sem["date_debut_iso"],
                            "date_fin_iso": sem["date_fin_iso"],
                        }
                    )

    columns_ids = (
        "dept",
        "etudid",
        "code_nip",
        "civilite_str",
        "nom",
        "prenom",
        "formsemestre_id",
        "date_debut_iso",
        "date_fin_iso",
    )
    tab = GenTable(columns_ids=columns_ids, rows=T)

    return tab.make_page(format=format, with_html_headers=False, publish=True)