#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Stashr - Forms
"""

"""
MIT License

Copyright (c) 2020 Andrew Vanderbye

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

"""-------------------------------------------------------------------------------------------
-- IMPORTS
-------------------------------------------------------------------------------------------"""

""" --- HUEY IMPORT --- """
""" --- PYTHON IMPORTS --- """
""" --- STASHR DEPENDENCY IMPORTS --- """
""" --- STASHR CORE IMPORTS --- """
from stashr import log, database

""" --- FLASK EXTENSION IMPORTS --- """
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired, FileAllowed

from wtforms import StringField, BooleanField, SelectField, IntegerField, HiddenField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError

from flask_bcrypt import check_password_hash, generate_password_hash

""" --- CREATE LOGGER --- """
logger = log.stashr_logger(__name__)

"""-------------------------------------------------------------------------------------------
-- FORM VALIDATIONS
-------------------------------------------------------------------------------------------"""

VALID_ROLES = [ 'admin',
                'librarian',
                'patron',
                'reader'
    ]

VALID_RATINGS = [ 'Everyone',
                  'Teen',
                  'Teen+',
                  'Parental Advisory',
                  'Explicit',
                  'Unrated'
]

VALID_LOGGING_LEVELS = [ 'CRITICAL',
                         'ERROR',
                         'WARNING',
                         'INFO',
                         'DEBUG']

def check_user_email(form, field):
    if database.session.query(database.Users).filter( (database.Users.username==field.data) | (database.Users.email==field.data) ).first() is None:
        raise ValidationError('Username/Email not found')


def dup_username_check(form, field):
    if database.session.query(database.Users).filter_by(username=field.data).first() is not None:
        raise ValidationError('Username already exists')


def dup_email_check(form, field):
    if database.session.query(database.Users).filter_by(email=field.data).first() is not None:
        raise ValidationError('Email already has an account')


def check_existing_email(form, field):
    if database.session.query(database.Users).filter_by(email=field.data).first() is None:
        raise ValidationError('Email not associated with account')


def update_email_check(form, field):
    # print(database.session.query(database.Users).filter_by(email=field.data).first().id)
    if int(database.session.query(database.Users).filter_by(email=field.data).first().id) != int(form.user_id.data):
        raise ValidationError('Email associated with a different account')


"""-------------------------------------------------------------------------------------------
-- FORMS
-------------------------------------------------------------------------------------------"""

""" --- USER FORMS --- """


# LOGIN FORM
class login_form(FlaskForm):
    username = StringField(
        'Username/Email',
        validators = [
            DataRequired(message='Please enter a Username'),
            check_user_email
        ]
    )
    password = StringField(
        'Password',
        validators = [
            DataRequired(message='Please enter a password')
        ]
    )
    remember_me = BooleanField(
        'Remember Me',
        validators = [
        ]
    )
    login_button = SubmitField(
        'Login'
    )


# REGISTRATION FORM
class registration_form(FlaskForm):
    username  = StringField(
        'Username',
        validators = [
            DataRequired(message='Please enter a Username'),
            Length(min=5, message='Username must be at least 5 characters'),
            dup_username_check
        ]
    )
    email = StringField(
        'Email',
        validators = [
            DataRequired(message='Please enter your email address'),
            Email(message='Please enter a valid email address'),
            dup_email_check
        ]
    )
    reg_password = StringField(
        'Password',
        validators = [
            DataRequired(message='Please enter a password'),
            Length(min=8, message='Password must be at least 8 characters')
        ]
    )
    confirm_reg_password = StringField(
        'Confirm Password',
        validators = [
            DataRequired(message='Please confirm your password'),
            Length(min=8),
            EqualTo('reg_password', message='Passwords must match')
        ]
    )

    register_button = SubmitField(
        'Register'
    )


# FORGOT PASSWORD FORM
class forgot_password_form(FlaskForm):
    email = StringField(
        'Email Address',
            validators = [
                DataRequired(message='Please enter your email address'),
                Email(message='Please enter a valid email address'),
                check_existing_email
            ]
        )
    forgot_button = SubmitField(
        'Send Email'
    )


class new_user_form(FlaskForm):
    
    username  = StringField(
        'Username',
        validators = [
            DataRequired(message='Please enter a Username'),
            Length(min=5, message='Username must be at least 5 characters'),
            dup_username_check
        ]
    )
    email = StringField(
        'Email',
        validators = [
            DataRequired(message='Please enter an email address'),
            Email(message='Please enter a valid email address'),
            dup_email_check
        ]
    )
    password = StringField(
        'Password',
        validators = [
            DataRequired(message='Please enter a password'),
            Length(min=8, message='Password must be at least 8 characters')
        ]
    )
    confirm_password = StringField(
        'Confirm Password',
        validators = [
            DataRequired(message='Please confirm your password'),
            Length(min=8),
            EqualTo('password', message='Passwords must match')
        ]
    )
    role = SelectField(
        'Role',
        choices = [
            (role, role) for role in VALID_ROLES
        ]
    )
    age_rating = SelectField(
        'Age Rating',
        choices = [
            (rating[0], rating[1]) for rating in database.ratings_dict_words.items()
        ]
    )

    new_user_button = SubmitField(
        'Create User'
    )


""" --- SETTINGS FORMS --- """


# UPDATE APP SETTINGS
class update_app_settings_form(FlaskForm):
    # open_registration - boolean
    open_registration = BooleanField(
        'Open Registration',
        validators = [
        ]
    )

    # server_port - int
    server_port = IntegerField(
        'Server Port',
        validators = [
        ]
    )

    # api_comicvine - string
    comicvine_api_key = StringField(
        'Comicvine API Key',
        validators=[
        ]
    )

    # debug level
    log_level = SelectField(
        'Logging Level',
        choices = [
            (level, level) for level in VALID_LOGGING_LEVELS
        ]
    )

    update_app_button = SubmitField(
        'Update'
    )


# UPDATE DIRECTORY SETTINGS
class update_directory_settings_form(FlaskForm):
    # temp
    temp_directory = StringField(
        'Temp Directory',
        validators=[
        ]
    )
    # comics
    comics_directory = StringField(
        'Comics Directory',
        validators=[
        ]
    )
    # log
    log_directory = StringField(
        'Log Directory',
        validators=[
        ]
    )
    # backup
    backup_directory = StringField(
        'Backup Directory',
        validators=[
        ]
    )
    # plugins
    plugins_directory = StringField(
        'Plugins Directory',
        validators=[
        ]
    )
    # images
    images_directory = StringField(
        'Images Directory',
        validators=[
        ]
    )

    update_directory_button = SubmitField(
        'Update'
    )



# UPDATE MAIL SETTINGS
class update_mail_settings_form(FlaskForm):

    mail_use = BooleanField(
        'Use Mail',
        validators = [
        ]
    )

    # mail_username - string
    mail_username = StringField(
        'Username',
        validators = [
        ]
    )
    # mail_password - string
    mail_password = StringField(
        'Password',
        validators = [
        ]
    )
    # mail_default_sender - string
    mail_default_sender = StringField(
        'Default Sender',
        validators = [
        ]
    )
    # mail_server - string
    mail_server = StringField(
        'Mail Server',
        validators = [
        ]
    )
    # mail_port - integer
    mail_port = IntegerField(
        'Port',
        validators = [
        ]
    )
    # mail_use_ssl - boolean
    mail_use_ssl = BooleanField(
        'Use SSL',
        validators = [
        ]
    )
    update_mail_button = SubmitField(
        'Update'
    )


# APP FIRST RUN FORM
class app_first_run_form(FlaskForm):

    username = StringField(
        'Admin Username',
        validators = [
            DataRequired(message='Administrative Username Required')
        ]
    )

    email = StringField(
        'E-Mail',
        validators = [
            DataRequired(message='Administrative E-Mail Required'),
            Email(message='Please enter a valid email address'),
        ]
    )

    password = StringField(
        'Password',
        validators = [
            DataRequired(message='Please enter a password'),
            Length(min=8, message='Password must be at least 8 characters')
        ]
    )

    confirm_password = StringField(
        'Confirm Password',
        validators = [
            DataRequired(message='Please enter a password'),
            Length(min=8, message='Password must be at least 8 characters'),
            EqualTo('password', message='Passwords must match')
        ]
    )

    comicvine_api_key = StringField(
        'Comivine API Key',
        validators = [
            DataRequired(message='Please enter your Comicvine API Key')
        ]
    )

    open_registration = BooleanField(
        'Enable Open Registration',
        validators = []
    )

    logging_level = SelectField(
        'Logging Level',
        choices=[
            (level, level) for level in VALID_LOGGING_LEVELS
        ]
    )

    first_run_button = SubmitField(
        'Save Settings'
    )

    """
    # App Logging
    app_logging = BooleanField(
        'Enable App Logging',
        validators = [
        ]
    )
    # App Open Registration
    app_open_registration = BooleanField(
        'Enable Open Registration',
        validators = [
        ]
    )
    # api_comicvine - string
    api_comicvine = StringField(
        'Comicvine API',
        validators = [
            DataRequired(message='Please enter your Comicvine API Key')
        ]
    )
    email = StringField(
        'Admin Email',
        validators = [
            DataRequired(message='Please enter your email address'),
            Email(message='Please enter a valid email address'),
            dup_email_check
        ]
    )
    app_logging_level = SelectField(
        'Logging Level',
        choices=[
            (level, level) for level in VALID_LOGGING_LEVELS
        ]
    )
    admin_fr_password = StringField(
        'Admin Password',
        validators = [
            DataRequired(message='Please enter a password'),
            Length(min=8, message='Password must be at least 8 characters')
        ]
    )
    confirm_admin_fr_password = StringField(
        'Confirm Admin Password',
        validators = [
            DataRequired(message='Please confirm your password'),
            Length(min=8),
            EqualTo('admin_fr_password', message='Passwords must match')
        ]
    )
    submit_first_button = SubmitField(
        'Save'
    )
    """

# Change Password Form
class change_password_form(FlaskForm):

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

    old_password = StringField(
        'Old Password',
        validators = [
            DataRequired(message='Please enter your password'),
            Length(min=8, message='Password must be at least 8 characters')
        ]
    )

    new_password = StringField(
        'New Password',
        validators = [
            DataRequired(message='Please enter a new password'),
            Length(min=8, message='Password must be at least 8 characters')
        ]
    )
    confirm_password = StringField(
        'Confirm New Password',
        validators = [
            DataRequired(message='Please confirm your new password'),
            Length(min=8, message='Password must be at least 8 characters'),
            EqualTo('new_password', message='Passwords must match')
        ]
    )

    update_password_button = SubmitField(
        'Update Password'
    )
    
    def validate_old_password(self, field):

        if not check_password_hash(self.user.password, field.data):
            raise ValidationError('Old Password Not Correct')
    

# Reset Password Form
class reset_password_form(FlaskForm):

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

    password = StringField(
        'Reset Password',
        validators = [
            DataRequired(message='Please enter a new password'),
            Length(min=8, message='Password must be at least 8 characters')
        ]
    )

    reset_password_button = SubmitField(
        'Reset Password'
    )

class delete_user_form(FlaskForm):

    def __init__(self, user, *args, **kwargs):
        super(delete_user_form, self).__init__(*args, **kwargs)
        self.user = user
    
    delete_user_button = SubmitField(
        'Delete User'
    )

class edit_user_form(FlaskForm):

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

    email = StringField(
        'User Email',
        validators = [
            DataRequired(message='Please enter your email address'),
            Email(message='Please enter a valid email address'),
        ]
    )

    role = SelectField(
        'Role',
        choices = [
            (role, role) for role in VALID_ROLES
        ]
    )
    age_rating = SelectField(
        'Age Rating',
        choices = [
            (rating[0], rating[1]) for rating in database.ratings_dict_words.items()
        ]
    )

    edit_user_button = SubmitField(
        'Edit User'
    )

    def validate_email(self, field):
        if field.data != self.user.email and database.session.query(database.Users).filter_by(email=field.data).first() is not None:
            raise ValidationError('Email already has an account')

""" --- UPLOAD FORMS --- """

# UPLOAD PLUGIN FORM
class upload_plugin_form(FlaskForm):
    plugin = FileField(
        'Upload Plugin Zip',
        validators=[FileRequired(),
                    FileAllowed(['zip'], 'ZIP File Format Required')]
    )
    upload_plugin_button = SubmitField(
        'Upload Plugin'
    )