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

Technology: View Models
Feature:    Base View Model

Description:
Base data model for views
"""

# IMPORTS
# VARIABLE INSTANTIATION
# METHODS

# IMPORTS
# internal
# from routes import bp_home
from business_objects.base import Base
from business_objects.tcg.user import User
from datastores.datastore_base import DataStore_Base
from datastores.datastore_user import DataStore_User
from helpers.helper_app import Helper_App
import lib.argument_validation as av
# external
from abc import ABC, abstractmethod
from flask_sqlalchemy import SQLAlchemy
from flask import Flask, session, current_app, jsonify
from pydantic import BaseModel, ConfigDict
from typing import ClassVar


class Model_View_Base(BaseModel, ABC):
    ATTR_DATA_AMOUNT: ClassVar[str] = 'data-amount'
    ATTR_TEXT_COLLAPSED: ClassVar[str] = 'textCollapsed'
    ATTR_TEXT_EXPANDED: ClassVar[str] = 'textExpanded'
    ATTR_USER_ID: ClassVar[str] = Base.ATTR_USER_ID
    ATTR_VALUE_CURRENT: ClassVar[str] = 'current-value'
    ATTR_VALUE_PREVIOUS: ClassVar[str] = 'previous-value'
    COLOUR_ACCENT: ClassVar[str] = '#C77DFF'
    COLOUR_ERROR: ClassVar[str] = 'red'
    COLOUR_PAGE_BACKGROUND: ClassVar[str] = '#E0AAFF'
    COLOUR_PAGE_BACKGROUND_1: ClassVar[str] = '#F5ECFE'
    COLOUR_PAGE_BACKGROUND_2: ClassVar[str] = '#FAE0E2'
    COLOUR_PRIMARY: ClassVar[str] = '#240046'
    COLOUR_SECONDARY: ClassVar[str] = '#3C096C'
    COLOUR_TEXT: ClassVar[str] = '#10002B'
    COLOUR_TEXT_BACKGROUND: ClassVar[str] = 'white'
    COLOUR_TEXT_LINK_UNVISITED: ClassVar[str] = '#0000EE'
    COLOUR_TEXT_LINK_VISITED: ClassVar[str] = '#551A8B'
    COMPANY_ADDRESS_SHORT: ClassVar[str] = 'Russet, Sawbridge Road, Grandborough, United Kingdom, CV23 8DN'
    COMPANY_NUMBER: ClassVar[str] = '13587499'
    DECK_ENTITY_TYPE_CODE: ClassVar[str] = 'deck'
    ENDPOINT_GET_ALTCHA_CHALLENGE: ClassVar[str] = 'routes_core_contact.create_altcha_challenge'
    ENDPOINT_PAGE_ACCESSIBILITY_REPORT: ClassVar[str] = 'routes_legal.accessibility_report'
    ENDPOINT_PAGE_ACCESSIBILITY_STATEMENT: ClassVar[str] = 'routes_legal.accessibility_statement'
    ENDPOINT_PAGE_DATA_RETENTION_SCHEDULE: ClassVar[str] = 'routes_legal.retention_schedule'
    ENDPOINT_PAGE_ERROR_NO_PERMISSION: ClassVar[str] = 'routes_core.error_no_permission'
    ENDPOINT_PAGE_HOME: ClassVar[str] = 'routes_mtg_game.home'
    ENDPOINT_PAGE_LICENSE: ClassVar[str] = 'routes_legal.license'
    ENDPOINT_PAGE_PRIVACY_POLICY: ClassVar[str] = 'routes_legal.privacy_policy'
    ENDPOINT_POST_COMMAND: ClassVar[str] = 'routes_core_contact.contact_post'
    FLAG_ACTIVE: ClassVar[str] = Base.FLAG_ACTIVE
    FLAG_ACTIVE_ONLY: ClassVar[str] = Base.FLAG_ACTIVE_ONLY
    FLAG_ADD: ClassVar[str] = 'add'
    # FLAG_ADD_DELETE: ClassVar[str] = 'add-delete'
    FLAG_BENEFITS: ClassVar[str] = 'benefits'
    FLAG_BOOL_FALSE: ClassVar[str] = 'false'
    FLAG_BOOL_TRUE: ClassVar[str] = 'true'
    # FLAG_BRIBE: ClassVar[str] = Bribe.FLAG_BRIBE
    FLAG_BUTTON: ClassVar[str] = 'button'
    FLAG_BUTTON_LIGHT: ClassVar[str] = 'button-light'
    FLAG_BUTTON_PRIMARY: ClassVar[str] = 'button-primary'
    FLAG_BUTTON_SUCCESS: ClassVar[str] = 'button-success'
    FLAG_CANCEL: ClassVar[str] = 'button-cancel'
    FLAG_CALLBACK: ClassVar[str] = 'callback'
    FLAG_CAPTCHA: ClassVar[str] = 'captcha'
    FLAG_CARD: ClassVar[str] = 'card'
    FLAG_CHECKBOX: ClassVar[str] = 'checkbox'
    FLAG_CLOSE_TEMPORARY_ELEMENT: ClassVar[str] = 'button-temporary-element-close'
    FLAG_CODE: ClassVar[str] = Base.FLAG_CODE
    FLAG_COLLAPSIBLE: ClassVar[str] = 'collapsible'
    FLAG_COLUMN: ClassVar[str] = 'column'
    FLAG_COMMENT: ClassVar[str] = 'comment'
    FLAG_CONTAINER: ClassVar[str] = 'container'
    FLAG_CONTAINER_ICON_AND_LABEL: ClassVar[str] = 'container-icon-label'
    FLAG_CONTAINER_INPUT: ClassVar[str] = 'container-input'
    # FLAG_CONTAINER_SAVE_CANCEL_BUTTONS: ClassVar[str] = 'container-save-cancel-buttons'
    FLAG_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
    FLAG_CTA_1: ClassVar[str] = 'cta-1'
    FLAG_CTA_2: ClassVar[str] = 'cta-2'
    FLAG_DATA: ClassVar[str] = 'data'
    FLAG_DATE_FROM: ClassVar[str] = Base.FLAG_DATE_FROM
    FLAG_DATE_TO: ClassVar[str] = Base.FLAG_DATE_TO
    FLAG_DDL_PREVIEW: ClassVar[str] = "ddl-preview"
    FLAG_DELETE: ClassVar[str] = 'delete'
    FLAG_DESCRIPTION: ClassVar[str] = Base.FLAG_DESCRIPTION
    FLAG_DETAIL: ClassVar[str] = 'detail'
    FLAG_DIALOG: ClassVar[str] = 'dialog'
    FLAG_DIRTY: ClassVar[str] = 'dirty'
    FLAG_DISPLAY_ORDER: ClassVar[str] = Base.FLAG_DISPLAY_ORDER
    FLAG_EDIT: ClassVar[str] = 'edit'
    FLAG_EMAIL: ClassVar[str] = Base.FLAG_EMAIL
    FLAG_END_ON: ClassVar[str] = Base.FLAG_END_ON
    FLAG_ERROR: ClassVar[str] = 'error'
    FLAG_EXPANDED: ClassVar[str] = 'expanded'
    FLAG_FAILURE: ClassVar[str] = 'failure'
    FLAG_FAQ: ClassVar[str] = 'faq'
    FLAG_FEATURES: ClassVar[str] = 'features'
    FLAG_FILTER: ClassVar[str] = 'filter'
    FLAG_FIRSTNAME: ClassVar[str] = Base.FLAG_FIRSTNAME
    FLAG_FORM: ClassVar[str] = 'form'
    FLAG_FORM_FILTERS: ClassVar[str] = 'form-filters'
    FLAG_HAMBURGER: ClassVar[str] = 'hamburger'
    FLAG_ICON: ClassVar[str] = "icon"
    FLAG_IMAGE_LOGO: ClassVar[str] = 'image-logo'
    FLAG_INITIALISED: ClassVar[str] = 'initialised'
    FLAG_INPUT_ANSWER: ClassVar[str] = 'input-answer'
    FLAG_IS_CHECKED: ClassVar[str] = 'is_checked'
    FLAG_IS_COLLAPSED: ClassVar[str] = 'is_collapsed'
    FLAG_LABEL_QUESTION: ClassVar[str] = 'label-question'
    FLAG_LEFT_HAND_STUB: ClassVar[str] = 'lhs'
    FLAG_LOGO: ClassVar[str] = 'logo'
    FLAG_MESSAGE: ClassVar[str] = 'message'
    FLAG_MODAL: ClassVar[str] = 'modal'
    FLAG_NAME: ClassVar[str] = Base.FLAG_NAME
    FLAG_NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME_ATTR_OPTION_TEXT
    FLAG_NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.FLAG_NAME_ATTR_OPTION_VALUE
    FLAG_NAME_PLURAL: ClassVar[str] = Base.FLAG_NAME_PLURAL
    # FLAG_NAME_SINGULAR: ClassVar[str] = Base.FLAG_NAME_SINGULAR
    FLAG_NAV_ADMIN_HOME: ClassVar[str] = 'navAdminHome'
    FLAG_NAV_MTG_DECKS: ClassVar[str] = 'navMtgDecks'
    FLAG_NAV_MTG_GAME: ClassVar[str] = 'navMtgGame'
    FLAG_NAV_MTG_GAMES: ClassVar[str] = 'navMtgGames'
    FLAG_NAV_MTG_HOME: ClassVar[str] = 'navMtgHome'
    FLAG_NAV_MTG_TRIAL_GAME: ClassVar[str] = 'navMtgTrialGame'
    FLAG_NAV_HOME: ClassVar[str] = 'navHome'
    FLAG_NAV_USER_ACCOUNT: ClassVar[str] = 'navUserAccount'
    FLAG_NAV_USER_ACCOUNT: ClassVar[str] = 'navUserAccounts'
    FLAG_NAV_USER_LOGIN: ClassVar[str] = 'navUserLogin'
    FLAG_NAV_USER_LOGOUT: ClassVar[str] = 'navUserLogout'
    FLAG_NOTES: ClassVar[str] = "notes"
    FLAG_OVERLAY: ClassVar[str] = 'overlay'
    FLAG_PAGE_BODY: ClassVar[str] = 'page-body'
    FLAG_PRICE: ClassVar[str] = Base.FLAG_PRICE
    FLAG_PRICING: ClassVar[str] = 'pricing'
    FLAG_QUANTITY: ClassVar[str] = 'quantity'
    FLAG_RIGHT_HAND_SIDE: ClassVar[str] = 'rhs'
    FLAG_ROW: ClassVar[str] = 'row'
    FLAG_ROW_NEW: ClassVar[str] = 'row-new'
    FLAG_ROWS: ClassVar[str] = Base.FLAG_ROWS
    FLAG_SAVE: ClassVar[str] = 'save'
    FLAG_SCROLLABLE: ClassVar[str] = 'scrollable'
    FLAG_SEARCH: ClassVar[str] = Base.FLAG_SEARCH
    FLAG_SLIDER: ClassVar[str] = 'slider'
    FLAG_START_ON: ClassVar[str] = Base.FLAG_START_ON
    FLAG_STATUS: ClassVar[str] = 'status'
    FLAG_SUBMIT: ClassVar[str] = 'submit'
    FLAG_SUCCESS: ClassVar[str] = 'success'
    FLAG_SURNAME: ClassVar[str] = Base.FLAG_SURNAME
    FLAG_TABLE_MAIN: ClassVar[str] = 'table-main'
    FLAG_TEMPORARY_ELEMENT: ClassVar[str] = 'temporary-element'
    FLAG_TESTIMONIAL: ClassVar[str] = 'testimonial'
    FLAG_USER: ClassVar[str] = User.FLAG_USER
    FLAG_VALUE: ClassVar[str] = Base.FLAG_VALUE
    # FLAG_VALUE_PROPOSITION: ClassVar[str] = 'value-proposition'
    FLAG_WEBSITE: ClassVar[str] = Base.FLAG_WEBSITE
    HASH_GET_ALTCHA_CHALLENGE: ClassVar[str] = '/altcha/create-challenge'
    HASH_PAGE_ACCESSIBILITY_REPORT: ClassVar[str] = '/accessibility-report'
    HASH_PAGE_ACCESSIBILITY_STATEMENT: ClassVar[str] = '/accessibility-statement'
    HASH_PAGE_DATA_RETENTION_SCHEDULE: ClassVar[str] = '/retention-schedule'
    HASH_PAGE_MTG_DECKS: ClassVar[str] = '/decks'
    HASH_PAGE_MTG_GAME: ClassVar[str] = '/game'
    HASH_PAGE_MTG_GAMES: ClassVar[str] = '/' # '/games'
    HASH_PAGE_MTG_HOME: ClassVar[str] = '/home'
    HASH_PAGE_MTG_TRIAL_GAME: ClassVar[str] = '/trial-game'
    HASH_PAGE_ERROR_NO_PERMISSION: ClassVar[str] = '/error'
    HASH_PAGE_LICENSE: ClassVar[str] = '/license'
    HASH_PAGE_PRIVACY_POLICY: ClassVar[str] = '/privacy-policy'
    HASH_PAGE_USER_ACCOUNT: ClassVar[str] = '/user/user'
    HASH_PAGE_USER_ACCOUNTS: ClassVar[str] = '/user/users'
    HASH_PAGE_USER_LOGIN: ClassVar[str] = '/login'
    HASH_PAGE_USER_LOGOUT: ClassVar[str] = '/logout'
    HASH_SAVE_MTG_GAME: ClassVar[str] = '/mtg/save-game'
    HASH_SAVE_MTG_GAME_PLAYER: ClassVar[str] = '/mtg/save-game-player'
    HASH_SAVE_MTG_GAME_ROUND: ClassVar[str] = '/mtg/save-game-round'
    HASH_SAVE_MTG_GAME_ROUND_PLAYER_DAMAGE: ClassVar[str] = '/mtg/save-game-round-player-damage'
    HASH_SAVE_MTG_DECK: ClassVar[str] = '/mtg/save-deck'
    HASH_SAVE_USER_USER: ClassVar[str] = '/user/save-user'
    ID_BUTTON_ADD: ClassVar[str] = 'buttonAdd'
    ID_BUTTON_APPLY_FILTERS: ClassVar[str] = 'buttonApplyFilters'
    ID_BUTTON_CANCEL: ClassVar[str] = 'buttonCancel'
    ID_BUTTON_HAMBURGER: ClassVar[str] = 'buttonHamburger'
    ID_BUTTON_SAVE: ClassVar[str] = 'buttonSave'
    ID_CONTAINER_TEMPLATE_ELEMENTS: ClassVar[str] = 'container-template-elements'
    ID_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
    ID_FORM_CONTACT: ClassVar[str] = 'formContact'
    ID_FORM_FILTERS: ClassVar[str] = 'formFilters'
    ID_LABEL_ERROR: ClassVar[str] = 'labelError'
    ID_OVERLAY_CONFIRM: ClassVar[str] = 'overlayConfirm'
    ID_OVERLAY_ERROR: ClassVar[str] = 'overlayError'
    ID_OVERLAY_HAMBURGER: ClassVar[str] = 'overlayHamburger'
    ID_PAGE_BODY: ClassVar[str] = 'pageBody'
    ID_TABLE_MAIN: ClassVar[str] = 'tableMain'
    ID_TEXTAREA_CONFIRM: ClassVar[str] = 'textareaConfirm'
    NAME_COMPANY: ClassVar[str] = 'Shuffle & Skirmish'
    NAME_COMPANY_SHORT: ClassVar[str] = 'Shuffle & Skirmish'
    NAME_CSRF_TOKEN: ClassVar[str] = 'csrf-token'
    USERNAME_DISCORD: ClassVar[str] = 'Fetch Metrics'
    USERNAME_FACEBOOK: ClassVar[str] = 'Fetch Metrics'
    USERNAME_GITHUB: ClassVar[str] = 'Teddy-1024'
    USERNAME_INSTAGRAM: ClassVar[str] = 'fetchmetrics'
    USERNAME_LINKEDIN: ClassVar[str] = 'fetchmetrics'
    USERNAME_REDDIT: ClassVar[str] = 'Fetch-Metrics'
    USERNAME_TIKTOK: ClassVar[str] = 'fetchmetrics'
    USERNAME_TWITTER: ClassVar[str] = 'FetchMetrics'
    URL_DISCORD: ClassVar[str] = f'https://discord.gg/HBSvutXSZf'
    URL_FACEBOOK: ClassVar[str] = 'https://www.facebook.com/profile.php?id=61579039227559'
    URL_GITHUB: ClassVar[str] = f'https://github.com/{USERNAME_GITHUB}'
    URL_INSTAGRAM: ClassVar[str] = f'https://www.instagram.com/{USERNAME_INSTAGRAM}/'
    URL_LINKEDIN: ClassVar[str] = f'https://www.linkedin.com/company/{USERNAME_LINKEDIN}'
    URL_LINKEDIN_PERSONAL: ClassVar[str] = f'https://www.linkedin.com/in/teddyms'
    URL_REDDIT: ClassVar[str] = f'https://www.reddit.com/u/{USERNAME_REDDIT}/s/gZKEz2ZwHN'
    URL_TIKTOK: ClassVar[str] = f'https://www.tiktok.com/@{USERNAME_TIKTOK}'
    URL_TWITTER: ClassVar[str] = f'https://x.com/{USERNAME_TWITTER}'
    USER_ENTITY_TYPE_CODE: ClassVar[str] = 'user'
    USER_DECK_LINK_ENTITY_TYPE_CODE: ClassVar[str] = 'user_deck_link'

    _title: str
    hash_page_current: str
    app: Flask = None
    session: None = None
    is_user_logged_in: bool = None
    user: User = None
    access_levels: list = None

    model_config = ConfigDict(arbitrary_types_allowed=True)

    @property
    # @abstractmethod
    def title(self):
        if self._title is None:
            raise NotImplementedError("Model Title required.")
        return self._title

    def __init__(self, hash_page_current, **kwargs):
        BaseModel.__init__(self, hash_page_current=hash_page_current, **kwargs)
        self.app = current_app
        with self.app.app_context():
            self.session = session
        # Helper_App.console_log(f'session: {self.session}')
        
        datastore_base = DataStore_Base()
        self.user = datastore_base.get_user_session()
        self.is_user_logged_in = self.user.get_is_logged_in()
        # Helper_App.console_log(f'model_view_base init end - model.user: {self.user}')
    
    def get_url_host(self):
        return self.app.config['URL_HOST']
        
    @staticmethod
    def output_bool(boolean):
        return str(boolean).lower()

    @staticmethod
    def get_user_session():
        datastore_user = DataStore_User()
        return datastore_user.get_user_session()

    @staticmethod
    def get_many_access_level(filters=None):
        _m = 'Model_View_Store.get_many_access_level'
        # av.val_instance(filters, 'filters', _m, Filters_Access_Level)
        access_levels, errors = DataStore_Base.get_many_access_level(filters)
        return access_levels
    @staticmethod
    def get_many_unit_measurement(filters=None):
        _m = 'Model_View_Store.get_many_unit_measurement'
        # av.val_instance(filters, 'filters', _m, Filters_Unit_Measurement)
        units_measurement, errors = DataStore_Base.get_many_unit_measurement(filters)
        return units_measurement
    
    @staticmethod
    def convert_list_objects_to_json(list_objects):
        return [obj.to_json() for obj in list_objects]
    @staticmethod
    def convert_list_objects_to_list_options(list_objects):
        return Base.convert_list_objects_to_list_options(list_objects)
    @staticmethod
    def convert_list_objects_to_dict_by_attribute_key(list_objects, key):
        return {getattr(obj, key): obj for obj in list_objects}
    @staticmethod
    def convert_list_objects_to_dict_json_by_attribute_key(list_objects, key):
        return {getattr(obj, key): obj.to_json() for obj in list_objects}
    @staticmethod
    def convert_list_objects_to_dict_by_attribute_key_default(list_objects):
        if list_objects is None or len(list_objects) == 0:
            return {}
        obj_class = list_objects[0].__class__
        return Model_View_Base.convert_list_objects_to_dict_by_attribute_key(list_objects, getattr(obj_class, obj_class.FLAG_NAME_ATTR_OPTION_VALUE))
    @staticmethod
    def convert_list_objects_to_dict_json_by_attribute_key_default(list_objects):
        if list_objects is None or len(list_objects) == 0:
            return {}
        obj_class = list_objects[0].__class__
        return Model_View_Base.convert_list_objects_to_dict_json_by_attribute_key(list_objects, getattr(obj_class, obj_class.FLAG_NAME_ATTR_OPTION_VALUE))
    @staticmethod
    def convert_dict_values_to_json(dict):
        return {key: dict[key].to_json() for key in dict.keys()}
    @staticmethod
    def convert_list_objects_to_preview_str(list_objects):
        preview_str = ''
        for obj in list_objects:
            if preview_str != '':
                preview_str += '\n'
            obj_json = obj.to_json()
            preview_str += obj_json[obj_json[Base.FLAG_NAME_ATTR_OPTION_TEXT]]
        return preview_str
    @staticmethod
    def join_with_linebreaks(strs):
        str_multiline = ''
        for str in strs:
            if str_multiline != '':
                str_multiline += '\n'
            str_multiline += str
        return str_multiline
    @staticmethod
    def format_date(date):
        if date is None:
            return ''
        return date.strftime('%Y-%m-%d')
    @staticmethod
    def format_datetime(date_time):
        if date_time is None:
            return ''
        return date_time.strftime('%Y-%m-%dT%H:%M')
    @staticmethod
    def format_datetime_text(date_time):
        if date_time is None:
            return ''
        return date_time.strftime('%d/%m/%Y %H:%M')
    @staticmethod
    def jsonify(data):
        return jsonify(data)
    def get_mail_contact_public(self):
        return self.app.config['MAIL_CONTACT_PUBLIC']
    @staticmethod
    def format_null_string_as_blank(string):
        return '' if string is None else string