import site
from typing import Type
from Modules.Inventory.inventory_model import inventory_contact, inventory_group, inventory_site
from cmath import log
from sqlalchemy import String, null
from sqlalchemy.ext.declarative import DeclarativeMeta
import persistence
import Model.model_manager as model_manager

from Modules.Inventory.inventory_model import inventory_item

from utility.app_logging import logger_name
import logging

logger = logging.getLogger(logger_name + ".INVENTORY")


def __create_object(jsonString : str, objectType, validated_func = None) :

    with persistence.get_Session_Instance() as sess :

        Item = objectType()
        model_manager.setModelItemAttributesFromJson(Item,jsonString)

        if validated_func != None :
            if not validated_func() :
                sess.rollback()

                logger.error("validation function returned false when creating object, may not be compliant : " + str(Item.__dict__))
                raise ("validation function returned false when creating object, may not be compliant : " + str(Item.__dict__))

        sess.add(Item)
        sess.commit()
        sess.refresh(Item)


        logger.debug("object of type '"  + str(type(Item)) + "' + created : " + str(Item.__dict__))

        return Item

def __update_object(object_id : int ,jsonString : str, objectType, validated_func = None) :

    with persistence.get_Session_Instance() as sess :

        Item = objectType()
        Item = sess.query(objectType).filter(objectType.id == object_id).first()
        if not isinstance(Item,objectType):
            raise BaseException(" object not found with id")
        model_manager.setModelItemAttributesFromJson(Item,jsonString)
        Item.id = object_id #the id have to remain the same. TODO add an ignore variable to the set attribute function.

        if validated_func != None :
            if not validated_func() :
                sess.rollback()
                logger.error("validation function returned false when updating object, may not be compliant"+ str(Item.__dict__))
                raise ("validation function returned false when updating object, may not be compliant "  + str(Item.__dict__))

        sess.commit()
        sess.refresh(Item)

        logger.debug("object of type '"  + str(type(Item)) + "' + updated : " + str(Item.__dict__))

        return Item


def __delete_object(object_id : int, objectType, validated_func = None) :

    with persistence.get_Session_Instance() as sess :

        Item = objectType()
        Item = sess.query(objectType).filter(objectType.id == object_id).first()
        sess.refresh(Item)
        if not isinstance(Item,objectType):
            raise BaseException(" object not found with id")

        item_dict = Item.__dict__
        item_id = Item.id

        sess.delete(Item)
        if validated_func != None :
            if not validated_func() :
                sess.rollback()
                logger.error("validation function returned false when deleting object, may not be compliant"  + str(Item.__dict__))
                raise ("validation function returned false when deleting object, may not be compliant"  + str(Item.__dict__))

        sess.commit()

        logger.debug("object of type '"  + str(type(objectType)) + "' + deleted : " + str(item_dict))

        return item_id


def __getItem(id : int ,objectype) :
    with persistence.get_Session_Instance() as sess :
        Item = sess.query(objectype).filter(objectype.id == id).first()
        if not isinstance(Item,objectype):
            raise BaseException("object not found with this id")


        return Item



#Items basic method
def inventory_item_create(jsonString : str) :

    Item =  __create_object(jsonString,inventory_item)
    #do some things here
    return Item


def inventory_item_update(inventory_id : int, jsonString : str) :
    Item = __update_object(inventory_id,jsonString,inventory_item)
    return Item



def inventory_item_delete(inventory_id : int, confirm = False):
    return __delete_object(inventory_id,inventory_item)


def get_inventory_item(inventory_id : int) :
    return __getItem(inventory_id,inventory_item)




def get_all_inventory_items() :

    with persistence.get_Session_Instance() as sess :
        Items = sess.query(inventory_item).order_by(inventory_item.id)

        return Items




#todo get item per page

#Sites basic method
def inventory_site_create(jsonString) :
    Item =  __create_object(jsonString,inventory_site)
    return Item

def inventory_site_update(site_id,jsonString) :
    Item =  __update_object(site_id,jsonString,inventory_site)
    return Item

def inventory_site_delete(site_id, confirm = False):
    return __delete_object(site_id,inventory_site)

def get_all_inventory_sites () :
    with persistence.get_Session_Instance() as sess :
        Sites = sess.query(inventory_site).order_by(inventory_site.id)

        return Sites

def get_inventory_site(site_id) :
    return __getItem(site_id,inventory_site)

#Contact basic method
def inventory_contact_create(jsonString) :
    Item =  __create_object(jsonString,inventory_contact)
    return Item

def inventory_contact_update(contact_id,jsonString) :
    Item =  __update_object(contact_id,jsonString,inventory_contact)
    return Item

def inventory_contact_delete(contact_id, confirm = False):
     return __delete_object(contact_id,inventory_contact)

def get_all_inventory_contacts() :
    with persistence.get_Session_Instance() as sess :
        Sites = sess.query(inventory_contact).order_by(inventory_contact.id)

        return Sites

def get_inventory_contact(contact_id) :
    return __getItem(contact_id,inventory_contact)


#Group basic method
def inventory_group_create(inventory_ids,jsonString) :
    group =  __create_object(jsonString,inventory_group)

    with persistence.get_Session_Instance() as sess :

        try :
            for id in inventory_ids :
                Item = sess.query(inventory_item).filter(inventory_item.id == id).first()
                Item.group_id = group.id
                sess.commit()
        except :
            sess.rollback()
            raise "one of input ID is not a valid ID for the group"



    return group

def inventory_group_add_item(group_id,inventory_id) :
    with persistence.get_Session_Instance() as sess :
        group = sess.query(inventory_group).filter(inventory_group.id == group_id).first()
        Item = sess.query(inventory_item).filter(inventory_item.id == inventory_id).first()
        Item.group_id = group.id

        sess.commit()


def inventory_group_delete_item(group_id,inventory_id) :
    with persistence.get_Session_Instance() as sess :

        group = sess.query(inventory_group).filter(inventory_group.id == group_id).first()
        Item = sess.query(inventory_item).filter(inventory_item.id == inventory_id).first()
        if group_id == Item.group_id :
            Item.group_id = None

        #TODO delete group if orphan ? maybe configure in model
        sess.commit()

def inventory_group_delete(group_id) :
    with persistence.get_Session_Instance() as sess :

        Items = sess.query(inventory_item).filter(inventory_item.group_id == group_id)

        for item in Items :
            item.group_id = None
        sess.commit()


        group = sess.query(inventory_group).filter(inventory_group.id == group_id).first()
        sess.delete(group)
        sess.commit()

    return group_id


def get_all_inventory_groups() :
    with persistence.get_Session_Instance() as sess :
        groups = sess.query(inventory_group).order_by(inventory_group.id)

        return groups

def get_inventory_group(group_id) :
    return __getItem(group_id,inventory_group)
