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

##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2021 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
#
##############################################################################

"""Import d'utilisateurs via fichier Excel
"""
import random, time

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header

from app.scodoc import sco_emails
import app.scodoc.sco_utils as scu
from app.scodoc.notes_log import log
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError, ScoException
from app.scodoc import sco_excel
from app.scodoc import sco_preferences
from app.scodoc import sco_users

TITLES = ("user_name", "nom", "prenom", "email", "roles", "dept")


def generate_excel_sample():
    """generates an excel document suitable to import users"""
    style = sco_excel.excel_make_style(bold=True)
    titles = TITLES
    titlesStyles = [style] * len(titles)
    return sco_excel.excel_simple_table(
        titles=titles, titlesStyles=titlesStyles, sheet_name="Utilisateurs ScoDoc"
    )


def import_excel_file(datafile, REQUEST=None, context=None):
    "Create users from Excel file"
    authuser = REQUEST.AUTHENTICATED_USER
    auth_name = str(authuser)
    authuser_info = context._user_list(args={"user_name": auth_name})
    zope_roles = authuser.getRolesInContext(context)
    if not authuser_info and not ("Manager" in zope_roles):
        # not admin, and not in database
        raise AccessDenied("invalid user (%s)" % auth_name)
    if authuser_info:
        auth_dept = authuser_info[0]["dept"]
    else:
        auth_dept = ""
    log("sco_import_users.import_excel_file by %s" % auth_name)

    exceldata = datafile.read()
    if not exceldata:
        raise ScoValueError("Ficher excel vide ou invalide")
    _, data = sco_excel.Excel_to_list(exceldata)
    if not data:  # probably a bug
        raise ScoException("import_excel_file: empty file !")
    # 1-  --- check title line
    fs = [scu.stripquotes(s).lower() for s in data[0]]
    log("excel: fs='%s'\ndata=%s" % (str(fs), str(data)))
    # check cols
    cols = {}.fromkeys(TITLES)
    unknown = []
    for tit in fs:
        if tit not in cols:
            unknown.append(tit)
        else:
            del cols[tit]
    if cols or unknown:
        raise ScoValueError(
            "colonnes incorrectes (on attend %d, et non %d) <br/> (colonnes manquantes: %s, colonnes invalides: %s)"
            % (len(TITLES), len(fs), list(cols.keys()), unknown)
        )
    # ok, same titles...
    U = []
    for line in data[1:]:
        d = {}
        for i in range(len(fs)):
            d[fs[i]] = line[i]
        U.append(d)

    return import_users(U, auth_dept=auth_dept, context=context)


def import_users(U, auth_dept="", context=None):
    """Import des utilisateurs:
    Pour chaque utilisateur à créer:
    - vérifier données
    - générer mot de passe aléatoire
    - créer utilisateur et mettre le mot de passe
    - envoyer mot de passe par mail

    En cas d'erreur: supprimer tous les utilisateurs que l'on vient de créer.
    """
    created = []  # liste de uid créés
    try:
        for u in U:
            ok, msg = sco_users.check_modif_user(
                0,
                user_name=u["user_name"],
                nom=u["nom"],
                prenom=u["prenom"],
                email=u["email"],
                roles=u["roles"],
            )
            if not ok:
                raise ScoValueError(
                    "données invalides pour %s: %s" % (u["user_name"], msg)
                )
            u["passwd"] = generate_password()
            # si auth_dept, crée tous les utilisateurs dans ce departement
            if auth_dept:
                u["dept"] = auth_dept
            #
            context.create_user(u.copy())
            created.append(u["user_name"])
    except:
        log("import_users: exception: deleting %s" % str(created))
        # delete created users
        for user_name in created:
            context._user_delete(user_name)
        raise  # re-raise exception

    for u in U:
        mail_password(u, context=context)

    return "ok"


#  --------- Génération du mot de passe initial -----------
# Adapté de http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440564
# Alphabet tres simple pour des mots de passe simples...


ALPHABET = r"""ABCDEFGHIJKLMNPQRSTUVWXYZ123456789123456789AEIOU"""
PASSLEN = 6
RNG = random.Random(time.time())


def generate_password():
    """This function creates a pseudo random number generator object, seeded with
    the cryptographic hash of the passString. The contents of the character set
    is then shuffled and a selection of passLength words is made from this list.
    This selection is returned as the generated password."""
    l = list(ALPHABET)  # make this mutable so that we can shuffle the characters
    RNG.shuffle(l)  # shuffle the character set
    # pick up only a subset from the available characters:
    return "".join(RNG.sample(l, PASSLEN))


def mail_password(u, context=None, reset=False):
    "Send password by email"
    if not u["email"]:
        return

    u["url"] = scu.ScoURL()

    txt = (
        """
Bonjour %(prenom)s %(nom)s,

"""
        % u
    )
    if reset:
        txt += (
            """
votre mot de passe ScoDoc a été ré-initialisé.

Le nouveau mot de passe est:  %(passwd)s
Votre nom d'utilisateur est %(user_name)s

Vous devrez changer ce mot de passe lors de votre première connexion 
sur %(url)s
"""
            % u
        )
    else:
        txt += (
            """
vous avez été déclaré comme utilisateur du logiciel de gestion de scolarité ScoDoc.

Votre nom d'utilisateur est %(user_name)s
Votre mot de passe est: %(passwd)s

Le logiciel est accessible sur: %(url)s

Vous êtes invité à changer ce mot de passe au plus vite (cliquez sur
votre nom en haut à gauche de la page d'accueil).
"""
            % u
        )

    txt += (
        """
        
ScoDoc est un logiciel libre développé à l'Université Paris 13 par Emmanuel Viennet.
Pour plus d'informations sur ce logiciel, voir %s

"""
        % scu.SCO_WEBSITE
    )
    msg = MIMEMultipart()
    if reset:
        msg["Subject"] = Header("Mot de passe ScoDoc", scu.SCO_ENCODING)
    else:
        msg["Subject"] = Header("Votre accès ScoDoc", scu.SCO_ENCODING)
    msg["From"] = sco_preferences.get_preference("email_from_addr")
    msg["To"] = u["email"]
    msg.epilogue = ""
    txt = MIMEText(txt, "plain", scu.SCO_ENCODING)
    msg.attach(txt)
    sco_emails.sendEmail(msg)
