"""
Project:    PARTS Website
Author:     Edward Middleton-Smith
            Precision And Research Technology Systems Limited

Technology: Business Objects
Feature:    User Business Object
"""

# internal
from business_objects.base import Base
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
import lib.argument_validation as av
from extensions import db
from forms.tcg.user import Filters_User
from helpers.helper_app import Helper_App
# external
from dataclasses import dataclass
from typing import ClassVar, Optional
from sqlalchemy.types import Text, Boolean


class User(SQLAlchemy_ABC, Base):
    ATTR_USER_AUTH0_ID: ClassVar[str] = 'user_auth0_id'
    FLAG_IS_EMAIL_VERIFIED: ClassVar[str] = 'is_email_verified'
    FLAG_IS_SUPER_USER: ClassVar[str] = 'is_super_user'
    FLAG_PRIORITY_ACCESS_LEVEL: ClassVar[str] = 'priority_access_level'
    NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME
    NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.ATTR_USER_ID

    __tablename__ = 'tcg_user'
    __table_args__ = { 'extend_existing': True }

    user_id = db.Column(db.Integer, primary_key=True)
    user_auth0_id = db.Column(db.String(250))
    firstname = db.Column(db.Text)
    surname = db.Column(db.Text)
    email = db.Column(db.String(256))
    is_email_verified = db.Column(db.Boolean)
    is_super_user = db.Column(db.Boolean)
    priority_access_level = db.Column(db.Integer)
    is_new = db.Column(db.Boolean)
    active = db.Column(db.Boolean)
    
    def __init__(self):
        self.user_id = 0
        self.is_new = False
        super().__init__()
    
    @classmethod
    def from_db_user(cls, query_row):
        """Map from PostgreSQL FN_TCG_User_Get_Many result columns:
        user_id, user_auth0_id, firstname, surname, email, is_email_verified,
        is_super_user, active, created_on, created_by_user_id, updated_last_on,
        updated_last_by_user_id, change_set_id
        """
        _m = f'{cls.__qualname__}.from_db_user'
        # Helper_App.console_log(f'user record: {query_row}')
        user = cls()
        user.user_id = query_row[0]
        user.user_auth0_id = query_row[1]
        user.firstname = query_row[2]
        user.surname = query_row[3]
        user.email = query_row[4]
        user.is_email_verified = av.input_bool(query_row[5], cls.FLAG_IS_EMAIL_VERIFIED, _m)
        user.is_super_user = av.input_bool(query_row[6], cls.FLAG_IS_SUPER_USER, _m)
        user.active = av.input_bool(query_row[7], 'active', _m)
        return user
        
    @classmethod
    def from_json(cls, json):
        _m = f'{cls.__qualname__}.from_json'
        user = cls()
        if json is None: return user
        # Helper_App.console_log(f'{_m}/n{json}')
        user.user_id = json[cls.ATTR_USER_ID]
        user.user_auth0_id = json[cls.ATTR_USER_AUTH0_ID]
        user.firstname = json[cls.FLAG_FIRSTNAME]
        user.surname = json[cls.FLAG_SURNAME]
        user.email = json[cls.FLAG_EMAIL]
        user.is_email_verified = av.input_bool(json[cls.FLAG_IS_EMAIL_VERIFIED], cls.FLAG_IS_EMAIL_VERIFIED, _m)
        user.is_super_user = av.input_bool(json[cls.FLAG_IS_SUPER_USER], cls.FLAG_IS_SUPER_USER, _m)
        return user
    
    @classmethod
    def from_json_auth0(cls, json):
        _m = f'{cls.__qualname__}.from_json_auth0'
        # Helper_App.console_log(_m)
        # Helper_App.console_log(f'JSON: {json}')
        user = cls()
        if json is None: return user
        user_info = json['userinfo']
        # Helper_App.console_log(f'user_info: {user_info}')
        user.user_id = None
        user.user_auth0_id = user_info['sub']
        user.firstname = None
        user.surname = None
        user.email = user_info[cls.FLAG_EMAIL]
        user.is_email_verified = av.input_bool(user_info['email_verified'], cls.FLAG_IS_EMAIL_VERIFIED, _m)
        user.is_super_user = None
        return user
    
    def to_json(self):
        as_json = {
            **self.get_shared_json_attributes(self)
            , self.ATTR_USER_ID: self.user_id
            , self.ATTR_USER_AUTH0_ID: self.user_auth0_id
            , self.FLAG_FIRSTNAME: self.firstname
            , self.FLAG_SURNAME: self.surname
            , self.FLAG_NAME: self.get_name()
            , self.FLAG_EMAIL: self.email
            , self.FLAG_IS_EMAIL_VERIFIED: self.is_email_verified
            , self.FLAG_IS_SUPER_USER: self.is_super_user
            , self.FLAG_PRIORITY_ACCESS_LEVEL: self.priority_access_level
        }
        return as_json
        
    def __repr__(self):
        return f'''
User (
      {self.ATTR_USER_ID}: {self.user_id}
    , {self.ATTR_USER_AUTH0_ID}: {self.user_auth0_id}
    , {self.FLAG_FIRSTNAME}: {self.firstname}
    , {self.FLAG_SURNAME}: {self.surname}
    , {self.FLAG_NAME}: {self.get_name()}
    , {self.FLAG_EMAIL}: {self.email}
    , {self.FLAG_IS_EMAIL_VERIFIED}: {self.is_email_verified}
    , {self.FLAG_IS_SUPER_USER}: {self.is_super_user}
    , {self.FLAG_PRIORITY_ACCESS_LEVEL}: {self.priority_access_level}
)           '''
    
    def get_is_logged_in(self):
        return (self.user_id is not None and self.user_id > 0 and self.user_id != Base.USER_ID_GUEST)
    
    def get_name(self):
        return f'{"" if self.firstname is None else self.firstname} {"" if self.surname is None else self.surname}'



class Parameters_User(Get_Many_Parameters_Base):
    # user_id: Optional[int]
    # auth0_user_id: str
    get_all_user: bool
    get_inactive_user: bool
    user_ids: str
    """
    user_auth0_ids: str
    names_user: str
    emails_user: str
    """
    require_all_id_filters_met: bool
    require_any_id_filters_met: bool
    # require_all_non_id_filters_met: bool
    # require_any_non_id_filters_met: bool


    @classmethod
    def from_form_filters_user(cls, form):
        _m = f'{cls.__qualname__}.from_form_filters_user'
        av.val_instance(form, 'form', _m, Filters_User)
        get_inactive = not av.input_bool(form.active_only.data, "active", _m)
        # user_id = '' if form.user_id.data is None else form.user_id.data
        filters = cls.get_default()
        filters.get_all_user = True # (user_id == '')
        filters.get_inactive_user = get_inactive
        filters.user_ids = '' # user_id
        # filters.user_auth0_ids = ''
        filters.require_all_id_filters_met = True
        filters.require_any_id_filters_met = True
        # filters.require_all_non_id_filters_met = False
        # filters.require_any_non_id_filters_met = True
        return filters
    
    @classmethod
    def from_user(cls, user):
        av.val_instance(user, 'user', 'Parameters_User.from_user', User)
        filters = cls.get_default()
        filters.get_all_user = ((user.user_id is None or user.user_id == 0) and user.user_auth0_id is None)
        filters.get_inactive_user = False
        filters.user_ids = '' if user.user_id is None else str(user.user_id)
        # filters.user_auth0_ids = user.user_auth0_id
        # filters.names_user = user.get_name()
        # filters.emails_user = user.email
        return filters
    
    @classmethod
    def get_default(cls):
        return cls(
              # user_id = None
            # , auth0_user_id = ''
              get_all_user = False
            , get_inactive_user = False
            , user_ids = ''
            # , user_auth0_ids = ''
            # , names_user = ''
            # , emails_user = ''
            , require_all_id_filters_met = True
            , require_any_id_filters_met = True
            # , require_all_non_id_filters_met = False
            # , require_any_non_id_filters_met = True
        )
    
    @classmethod
    def from_json(self):
        pass
    def to_json(self):
        return {
            # 'a_user_id': self.user_id
            # , 'a_auth0_user_id': self.auth0_user_id
              'a_get_all_user': self.get_all_user
            , 'a_get_inactive_user': self.get_inactive_user
            , 'a_user_ids': self.user_ids
            # , 'a_user_auth0_ids': self.user_auth0_ids
            # , 'a_names_user': self.names_user
            # , 'a_emails_user': self.emails_user
            , 'a_require_all_id_filters_met': self.require_all_id_filters_met
            , 'a_require_any_id_filters_met': self.require_any_id_filters_met
            # , 'a_require_all_non_id_filters_met': self.require_all_non_id_filters_met
            # , 'a_require_any_non_id_filters_met': self.require_any_non_id_filters_met
        }
    @staticmethod
    def get_type_hints():
        return {
              'a_get_all_user': Boolean
            , 'a_get_inactive_user': Boolean
            , 'a_user_ids': Text
            , 'a_require_all_id_filters_met': Boolean
            , 'a_require_any_id_filters_met': Boolean
        }