# -*- 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
#
#
##############################################################################

import re
import requests

from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed, FileRequired
from markupsafe import Markup
from sqlalchemy import text
from wtforms import (
    StringField,
    SubmitField,
    TextAreaField,
    SelectField,
    HiddenField,
    SelectMultipleField,
    DateField,
    BooleanField,
)
from wtforms.validators import ValidationError, DataRequired, Email, Optional
from wtforms.widgets import ListWidget, CheckboxInput

from app.entreprises.models import Entreprise, EntrepriseContact, EntreprisePreferences
from app.models import Identite, Departement
from app.auth.models import User

CHAMP_REQUIS = "Ce champ est requis"
SUBMIT_MARGE = {"style": "margin-bottom: 10px;"}


def _build_string_field(label, required=True, render_kw=None):
    if required:
        return StringField(
            label,
            validators=[DataRequired(message=CHAMP_REQUIS)],
            render_kw=render_kw,
        )
    else:
        return StringField(label, validators=[Optional()], render_kw=render_kw)


class EntrepriseCreationForm(FlaskForm):
    siret = _build_string_field(
        "SIRET (*)",
        render_kw={"placeholder": "Numéro composé de 14 chiffres", "maxlength": "14"},
    )
    nom_entreprise = _build_string_field("Nom de l'entreprise (*)")
    adresse = _build_string_field("Adresse de l'entreprise (*)")
    codepostal = _build_string_field("Code postal de l'entreprise (*)")
    ville = _build_string_field("Ville de l'entreprise (*)")
    pays = _build_string_field("Pays de l'entreprise", required=False)

    nom_contact = _build_string_field("Nom du contact (*)")
    prenom_contact = _build_string_field("Prénom du contact (*)")
    telephone = _build_string_field("Téléphone du contact (*)", required=False)
    mail = StringField(
        "Mail du contact (*)",
        validators=[Optional(), Email(message="Adresse e-mail invalide")],
    )
    poste = _build_string_field("Poste du contact", required=False)
    service = _build_string_field("Service du contact", required=False)
    submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)

    def validate(self):
        validate = True
        if not FlaskForm.validate(self):
            validate = False

        if not self.telephone.data and not self.mail.data:
            self.telephone.errors.append(
                "Saisir un moyen de contact (mail ou téléphone)"
            )
            self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)")
            validate = False

        return validate

    def validate_siret(self, siret):
        if EntreprisePreferences.get_check_siret():
            siret = siret.data.strip()
            if re.match("^\d{14}$", siret) is None:
                raise ValidationError("Format incorrect")
            try:
                req = requests.get(
                    f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}"
                )
            except requests.ConnectionError:
                print("no internet")
            if req.status_code != 200:
                raise ValidationError("SIRET inexistant")
            entreprise = Entreprise.query.filter_by(siret=siret).first()
            if entreprise is not None:
                lien = f'<a href="/ScoDoc/entreprises/fiche_entreprise/{entreprise.id}">ici</a>'
                raise ValidationError(
                    Markup(f"Entreprise déjà présent, lien vers la fiche : {lien}")
                )


class EntrepriseModificationForm(FlaskForm):
    hidden_entreprise_siret = HiddenField()
    siret = StringField("SIRET (*)")
    nom = _build_string_field("Nom de l'entreprise (*)")
    adresse = _build_string_field("Adresse (*)")
    codepostal = _build_string_field("Code postal (*)")
    ville = _build_string_field("Ville (*)")
    pays = _build_string_field("Pays", required=False)
    submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.siret.render_kw = {
            "disabled": "",
            "value": self.hidden_entreprise_siret.data,
        }


class MultiCheckboxField(SelectMultipleField):
    widget = ListWidget(prefix_label=False)
    option_widget = CheckboxInput()


class OffreCreationForm(FlaskForm):
    intitule = _build_string_field("Intitulé (*)")
    description = TextAreaField(
        "Description (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
    )
    type_offre = SelectField(
        "Type de l'offre (*)",
        choices=[("Stage"), ("Alternance")],
        validators=[DataRequired(message=CHAMP_REQUIS)],
    )
    missions = TextAreaField(
        "Missions (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
    )
    duree = _build_string_field("Durée (*)")
    depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int)
    expiration_date = DateField("Date expiration", validators=[Optional()])
    submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.depts.choices = [
            (dept.id, dept.acronym) for dept in Departement.query.all()
        ]


class OffreModificationForm(FlaskForm):
    intitule = _build_string_field("Intitulé (*)")
    description = TextAreaField(
        "Description (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
    )
    type_offre = SelectField(
        "Type de l'offre (*)",
        choices=[("Stage"), ("Alternance")],
        validators=[DataRequired(message=CHAMP_REQUIS)],
    )
    missions = TextAreaField(
        "Missions (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
    )
    duree = _build_string_field("Durée (*)")
    depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int)
    expiration_date = DateField("Date expiration", validators=[Optional()])
    submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.depts.choices = [
            (dept.id, dept.acronym) for dept in Departement.query.all()
        ]


class ContactCreationForm(FlaskForm):
    hidden_entreprise_id = HiddenField()
    nom = _build_string_field("Nom (*)")
    prenom = _build_string_field("Prénom (*)")
    telephone = _build_string_field("Téléphone (*)", required=False)
    mail = StringField(
        "Mail (*)",
        validators=[Optional(), Email(message="Adresse e-mail invalide")],
    )
    poste = _build_string_field("Poste", required=False)
    service = _build_string_field("Service", required=False)
    submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)

    def validate(self):
        validate = True
        if not FlaskForm.validate(self):
            validate = False

        contact = EntrepriseContact.query.filter_by(
            entreprise_id=self.hidden_entreprise_id.data,
            nom=self.nom.data,
            prenom=self.prenom.data,
        ).first()
        if contact is not None:
            self.nom.errors.append("Ce contact existe déjà (même nom et prénom)")
            self.prenom.errors.append("")
            validate = False

        if not self.telephone.data and not self.mail.data:
            self.telephone.errors.append(
                "Saisir un moyen de contact (mail ou téléphone)"
            )
            self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)")
            validate = False

        return validate


class ContactModificationForm(FlaskForm):
    hidden_contact_id = HiddenField()
    hidden_entreprise_id = HiddenField()
    nom = _build_string_field("Nom (*)")
    prenom = _build_string_field("Prénom (*)")
    telephone = _build_string_field("Téléphone (*)", required=False)
    mail = StringField(
        "Mail (*)",
        validators=[Optional(), Email(message="Adresse e-mail invalide")],
    )
    poste = _build_string_field("Poste", required=False)
    service = _build_string_field("Service", required=False)
    submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)

    def validate(self):
        validate = True
        if not FlaskForm.validate(self):
            validate = False

        contact = EntrepriseContact.query.filter(
            EntrepriseContact.id != self.hidden_contact_id.data,
            EntrepriseContact.entreprise_id == self.hidden_entreprise_id.data,
            EntrepriseContact.nom == self.nom.data,
            EntrepriseContact.prenom == self.prenom.data,
        ).first()
        if contact is not None:
            self.nom.errors.append("Ce contact existe déjà (même nom et prénom)")
            self.prenom.errors.append("")
            validate = False

        if not self.telephone.data and not self.mail.data:
            self.telephone.errors.append(
                "Saisir un moyen de contact (mail ou téléphone)"
            )
            self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)")
            validate = False

        return validate


class HistoriqueCreationForm(FlaskForm):
    etudiant = _build_string_field(
        "Étudiant (*)",
        render_kw={"placeholder": "Tapez le nom de l'étudiant"},
    )
    type_offre = SelectField(
        "Type de l'offre (*)",
        choices=[("Stage"), ("Alternance")],
        validators=[DataRequired(message=CHAMP_REQUIS)],
    )
    date_debut = DateField(
        "Date début (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
    )
    date_fin = DateField(
        "Date fin (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
    )
    submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)

    def validate(self):
        validate = True
        if not FlaskForm.validate(self):
            validate = False

        if (
            self.date_debut.data
            and self.date_fin.data
            and self.date_debut.data > self.date_fin.data
        ):
            self.date_debut.errors.append("Les dates sont incompatibles")
            self.date_fin.errors.append("Les dates sont incompatibles")
            validate = False

        return validate

    def validate_etudiant(self, etudiant):
        etudiant_data = etudiant.data.upper().strip()
        stm = text(
            "SELECT id, CONCAT(nom, ' ', prenom) as nom_prenom FROM Identite WHERE CONCAT(nom, ' ', prenom)=:nom_prenom"
        )
        etudiant = (
            Identite.query.from_statement(stm).params(nom_prenom=etudiant_data).first()
        )
        if etudiant is None:
            raise ValidationError("Champ incorrect (selectionnez dans la liste)")


class EnvoiOffreForm(FlaskForm):
    responsable = _build_string_field(
        "Responsable de formation (*)",
        render_kw={"placeholder": "Tapez le nom du responsable de formation"},
    )
    submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)

    def validate_responsable(self, responsable):
        responsable_data = responsable.data.upper().strip()
        stm = text(
            "SELECT id, UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')')) FROM \"user\" WHERE UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')'))=:responsable_data"
        )
        responsable = (
            User.query.from_statement(stm)
            .params(responsable_data=responsable_data)
            .first()
        )
        if responsable is None:
            raise ValidationError("Champ incorrect (selectionnez dans la liste)")


class AjoutFichierForm(FlaskForm):
    fichier = FileField(
        "Fichier (*)",
        validators=[
            FileRequired(message=CHAMP_REQUIS),
            FileAllowed(["pdf", "docx"], "Fichier .pdf ou .docx uniquement"),
        ],
    )
    submit = SubmitField("Ajouter", render_kw=SUBMIT_MARGE)


class SuppressionConfirmationForm(FlaskForm):
    submit = SubmitField("Supprimer", render_kw=SUBMIT_MARGE)


class ValidationConfirmationForm(FlaskForm):
    submit = SubmitField("Valider", render_kw=SUBMIT_MARGE)


class ImportForm(FlaskForm):
    fichier = FileField(
        "Fichier (*)",
        validators=[
            FileRequired(message=CHAMP_REQUIS),
            FileAllowed(["xlsx"], "Fichier .xlsx uniquement"),
        ],
    )
    submit = SubmitField("Importer", render_kw=SUBMIT_MARGE)


class PreferencesForm(FlaskForm):
    mail_entreprise = StringField(
        "Mail notifications",
        validators=[Optional(), Email(message="Adresse e-mail invalide")],
    )
    check_siret = BooleanField("Vérification SIRET")
    submit = SubmitField("Valider", render_kw=SUBMIT_MARGE)