from flask import current_app, session
from flask_wtf import FlaskForm
from wtforms import (StringField, BooleanField, SubmitField, EmailField, IntegerField, DateField,
                     SelectField, SelectMultipleField, FieldList, FormField, TextAreaField)
from wtforms.validators import DataRequired, Length, Email, NumberRange, Optional, ValidationError
import pytz
from flask_security import current_user
from wtforms.widgets.core import HiddenInput

from common.models.user import TenantMake
from common.services.user import UserServices
from config.type_defs.service_types import SERVICE_TYPES
from eveai_app.views.dynamic_form_base import DynamicFormBase


class TenantForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired(), Length(max=80)])
    code = StringField('Code', validators=[DataRequired()], render_kw={'readonly': True})
    type = SelectField('Tenant Type', validators=[Optional()], default='Active')
    website = StringField('Website', validators=[DataRequired(), Length(max=255)])
    # invoicing fields
    currency = SelectField('Currency', choices=[], validators=[DataRequired()])
    # Timezone
    timezone = SelectField('Timezone', choices=[], validators=[DataRequired()])

    # For Super Users only - Allow to assign the tenant to the partner
    assign_to_partner = BooleanField('Assign to Partner', default=False)
    # Embedding variables
    submit = SubmitField('Submit')

    def __init__(self, *args, **kwargs):
        super(TenantForm, self).__init__(*args, **kwargs)
        # initialise currency field
        self.currency.choices = [(curr, curr) for curr in current_app.config['SUPPORTED_CURRENCIES']]
        # initialise timezone
        self.timezone.choices = [(tz, tz) for tz in pytz.common_timezones]
        # Initialize fallback algorithms
        self.type.choices = [(t, t) for t in current_app.config['TENANT_TYPES']]
        # Initialize default tenant make choices
        tenant_id = session.get('tenant', {}).get('id') if 'tenant' in session else None
        # Show field only for Super Users with partner in session
        if not current_user.has_roles('Super User') or 'partner' not in session:
            self._fields.pop('assign_to_partner', None)


class EditTenantForm(FlaskForm):
    id = IntegerField('ID', widget=HiddenInput())
    name = StringField('Name', validators=[DataRequired(), Length(max=80)])
    code = StringField('Code', validators=[DataRequired()], render_kw={'readonly': True})
    type = SelectField('Tenant Type', validators=[Optional()], default='Active')
    website = StringField('Website', validators=[DataRequired(), Length(max=255)])
    # invoicing fields
    currency = SelectField('Currency', choices=[], validators=[DataRequired()])
    # Timezone
    timezone = SelectField('Timezone', choices=[], validators=[DataRequired()])
    # Default tenant make
    default_tenant_make_id = SelectField('Default Tenant Make', choices=[], validators=[Optional()])

    # For Super Users only - Allow to assign the tenant to the partner
    assign_to_partner = BooleanField('Assign to Partner', default=False)
    # Embedding variables
    submit = SubmitField('Submit')

    def __init__(self, *args, **kwargs):
        super(EditTenantForm, self).__init__(*args, **kwargs)
        # initialise currency field
        self.currency.choices = [(curr, curr) for curr in current_app.config['SUPPORTED_CURRENCIES']]
        # initialise timezone
        self.timezone.choices = [(tz, tz) for tz in pytz.common_timezones]
        # Initialize fallback algorithms
        self.type.choices = [(t, t) for t in current_app.config['TENANT_TYPES']]
        # Initialize default tenant make choices
        tenant_id = self.id.data
        if tenant_id:
            tenant_makes = TenantMake.query.filter_by(tenant_id=tenant_id, active=True).all()
            self.default_tenant_make_id.choices = [(str(make.id), make.name) for make in tenant_makes]
            # Add empty choice
            self.default_tenant_make_id.choices.insert(0, ('', 'Geen'))
        # Show field only for Super Users with partner in session
        if not current_user.has_roles('Super User') or 'partner' not in session:
            self._fields.pop('assign_to_partner', None)


class BaseUserForm(FlaskForm):
    user_name = StringField('Name', validators=[DataRequired(), Length(max=80)])
    email = EmailField('Email', validators=[DataRequired(), Email()])
    first_name = StringField('First Name', validators=[DataRequired(), Length(max=80)])
    last_name = StringField('Last Name', validators=[DataRequired(), Length(max=80)])
    valid_to = DateField('Valid to', id='form-control datepicker', validators=[Optional()])
    tenant_id = IntegerField('Tenant ID', validators=[NumberRange(min=0)])
    roles = SelectMultipleField('Roles', coerce=int)
    is_primary_contact = BooleanField('Primary Contact')
    is_financial_contact = BooleanField('Financial Contact')

    def __init__(self, *args, **kwargs):
        super(BaseUserForm, self).__init__(*args, **kwargs)
        self.roles.choices = UserServices.get_assignable_roles()


class CreateUserForm(BaseUserForm):
    submit = SubmitField('Create User')


class EditUserForm(BaseUserForm):
    # Some R/O informational fields
    confirmed_at = DateField('Confirmed At', id='form-control datepicker', validators=[Optional()],
                             render_kw={'readonly': True})
    last_login_at = DateField('Last Login At', id='form-control datepicker', validators=[Optional()],
                              render_kw={'readonly': True})
    login_count = IntegerField('Login Count', validators=[Optional()], render_kw={'readonly': True})
    submit = SubmitField('Save User')


class RoleForm(FlaskForm):
    # This subform will represent a single checkbox for each role
    role_id = StringField('Role ID')
    checked = BooleanField('Assigned')


class UserRoleForm(FlaskForm):
    email = EmailField('Email', validators=[DataRequired(), Email()])
    roles = FieldList(FormField(RoleForm), min_entries=1)
    submit = SubmitField('Update Roles')


class TenantDomainForm(FlaskForm):
    domain = StringField('Domain', validators=[DataRequired(), Length(max=80)])
    valid_to = DateField('Valid to', id='form-control datepicker', validators=[Optional()])
    submit = SubmitField('Add Domain')


class TenantSelectionForm(FlaskForm):
    types = SelectMultipleField('Tenant Types', choices=[], validators=[Optional()])
    search = StringField('Search', validators=[Optional()])
    submit = SubmitField('Filter')

    def __init__(self, *args, **kwargs):
        super(TenantSelectionForm, self).__init__(*args, **kwargs)
        self.types.choices = [(t, t) for t in current_app.config['TENANT_TYPES']]


class TenantProjectForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired(), Length(max=50)])
    description = TextAreaField('Description', validators=[Optional()])
    services = SelectMultipleField('Allowed Services', choices=[], validators=[DataRequired()])
    unencrypted_api_key = StringField('Unencrypted API Key', validators=[DataRequired()], render_kw={'readonly': True})
    visual_api_key = StringField('Visual API Key', validators=[DataRequired()], render_kw={'readonly': True})
    active = BooleanField('Active', validators=[Optional()], default=True)
    responsible_email = EmailField('Responsible Email', validators=[Optional(), Email()])

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Initialize choices for the services field
        self.services.choices = [(key, value['description']) for key, value in SERVICE_TYPES.items()]


class EditTenantProjectForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired(), Length(max=50)])
    description = TextAreaField('Description', validators=[Optional()])
    services = SelectMultipleField('Allowed Services', choices=[], validators=[DataRequired()])
    visual_api_key = StringField('Visual API Key', validators=[DataRequired()], render_kw={'readonly': True})
    active = BooleanField('Active', validators=[Optional()], default=True)
    responsible_email = EmailField('Responsible Email', validators=[Optional(), Email()])

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Initialize choices for the services field
        self.services.choices = [(key, value['description']) for key, value in SERVICE_TYPES.items()]


def validate_make_name(form, field):
    # Check if tenant_make already exists in the database
    existing_make = TenantMake.query.filter_by(name=field.data).first()

    if existing_make:
        if not hasattr(form, 'id') or form.id.data != existing_make.id:
            raise ValidationError(f'A Make with name "{field.data}" already exists. Choose another name.')


class TenantMakeForm(DynamicFormBase):
    name = StringField('Name', validators=[DataRequired(), Length(max=50), validate_make_name])
    description = TextAreaField('Description', validators=[Optional()])
    active = BooleanField('Active', validators=[Optional()], default=True)
    website = StringField('Website', validators=[DataRequired(), Length(max=255)])
    logo_url = StringField('Logo URL', validators=[Optional(), Length(max=255)])
    allowed_languages = SelectMultipleField('Allowed Languages', choices=[], validators=[Optional()])

    def __init__(self, *args, **kwargs):
        super(TenantMakeForm, self).__init__(*args, **kwargs)
        # Initialiseer de taalopties met taalcodes en vlaggen
        lang_details = current_app.config['SUPPORTED_LANGUAGE_DETAILS']
        self.allowed_languages.choices = [(details['iso 639-1'], f"{details['flag']} {details['iso 639-1']}") 
                                         for name, details in lang_details.items()]


class EditTenantMakeForm(DynamicFormBase):
    id = IntegerField('ID', widget=HiddenInput())
    name = StringField('Name', validators=[DataRequired(), Length(max=50), validate_make_name])
    description = TextAreaField('Description', validators=[Optional()])
    active = BooleanField('Active', validators=[Optional()], default=True)
    website = StringField('Website', validators=[DataRequired(), Length(max=255)])
    logo_url = StringField('Logo URL', validators=[Optional(), Length(max=255)])
    default_language = SelectField('Default Language', choices=[], validators=[DataRequired()])
    allowed_languages = SelectMultipleField('Allowed Languages', choices=[], validators=[Optional()])

    def __init__(self, *args, **kwargs):
        super(EditTenantMakeForm, self).__init__(*args, **kwargs)
        # Initialiseer de taalopties met taalcodes en vlaggen
        lang_details = current_app.config['SUPPORTED_LANGUAGE_DETAILS']
        choices = [(details['iso 639-1'], f"{details['flag']} {details['iso 639-1']}")
                   for name, details in lang_details.items()]
        self.allowed_languages.choices = choices
        self.default_language.choices = choices


class ConsentVersionForm(FlaskForm):
    consent_type = SelectField('Consent Type', choices=[], validators=[DataRequired()])
    consent_version = StringField('Consent Version', validators=[DataRequired(), Length(max=20)])
    consent_valid_from = DateField('Consent Valid From', id='form-control datepicker', validators=[DataRequired()])
    consent_valid_to = DateField('Consent Valid To', id='form-control datepicker', validators=[Optional()])

    def __init__(self, *args, **kwargs):
        super(ConsentVersionForm, self).__init__(*args, **kwargs)
        # Initialise consent types
        self.consent_type.choices = [(t, t) for t in current_app.config['CONSENT_TYPES']]


class EditConsentVersionForm(FlaskForm):
    consent_type = StringField('Consent Type', validators=[DataRequired()])
    consent_version = StringField('Consent Version', validators=[DataRequired(), Length(max=20)])
    consent_valid_from = DateField('Consent Valid From', id='form-control datepicker', validators=[DataRequired()])
    consent_valid_to = DateField('Consent Valid To', id='form-control datepicker', validators=[Optional()])

