from os import environ as env
import numpy as np
import traceback

from AvenirCommon.Database import *
from AvenirCommon.Logger import *
from SpectrumCommon.Const.GB import GB_MOD_STR, GB_PJ, GB_SW_BADGETMODVARS, GB_SW_BADSETMODVARS
from SpectrumCommon.Const.PJ import PJN_ModulesTag
from .MakeAuthenticatedCalls import make_post
from SpectrumCommon.ServerUtils.ExceptionUtils import SpectrumException


def get_modvars(filter_packet):
    return make_post(env['AVENIR_SW_FILTER_URL'] +'/api/v1/getModvars', filter_packet)


def set_modvars(filter_packet):
    return make_post(env['AVENIR_SW_FILTER_URL'] +'/api/v1/setModvars', filter_packet)

def get_pjn_modvars(projID):
    return GB_get_db_json(env['AVENIR_SW_STATE_DB_CONNECTION'], 'projections', projID+ '/PJ.JSON')

def get_all_modvars(projID):
    projection = GB_get_db_json(env['AVENIR_SW_STATE_DB_CONNECTION'], 'projections', projID+ '/PJ.JSON')
    for mod_int in projection[PJN_ModulesTag]:
        if mod_int != GB_PJ:
            projection.update(GB_get_db_json(env['AVENIR_SW_STATE_DB_CONNECTION'], 'projections', projID+ '/'+GB_MOD_STR[mod_int]+'.JSON'))

    _dtype = np.float64
    dt = np.dtype(np.float64)  
    for tag in projection:
        if type(projection[tag]) == list:
            try:
                if len(projection[tag])>0 and ((type(projection[tag][0])==dict) or(type(projection[tag][0])==str)) :
                    projection[tag] = np.array(projection[tag], order='C')#, dtype = dt)
                else:
                    projection[tag] = np.array(projection[tag], order='C', dtype=dt)#, dtype = dt)
            
            except:
                log('Failed to convert list to numpy array '+tag)
                projection[tag] = projection[tag] #nop
                 
    return projection

def get_calc_modvars(projID, mod_tags, modvars=None):
    try:
        _dtype = np.float64
        dt = np.dtype(np.float64)  
        if modvars==None:
            modvars = GB_get_db_json(env['AVENIR_SW_STATE_DB_CONNECTION'], 'projections', projID+ '/PJ.JSON')
    
        packet = {
            "projID": projID,
            "modules": [{"module": GB_MOD_STR[mod_id], "modvars": mod_tags[mod_id] } for mod_id in modvars[PJN_ModulesTag] if (mod_id in mod_tags)]
            }
        response = get_modvars(packet)
        
        modules = ujson.loads(response.body)['result']
        for md in modules:
            for mv in md['modvars']:
                if ('value' in mv):
                    # print(mv['tag'])
                    if type(mv['value']) == list:
                        try:
                            if len(mv['value'])>0 and ((type(mv['value'][0])==dict) or(type(mv['value'][0])==str) or(type(mv['value'][0])==bool)) :
                                mv['value'] = np.array(mv['value'], order='C')#, dtype = dt)
                            else:
                                mv['value'] = np.array(mv['value'], order='C', dtype=dt)#, dtype = dt)
                        
                        except:
                            log('Failed to convert list to numpy array '+mv['tag'])
                            try: #try one more time
                                mv['value'] = np.array(mv['value'])#, dtype = dt)
                            except:
                                log('Failed Second  time to convert list to numpy array '+mv['tag'])
                                
                            mv['value'] = mv['value'] #nop

                        
                    
                    modvar = {mv['tag']:mv['value']}
                    modvars.update(modvar)
                
                
        # modvars = GB_get_db_json(env['AVENIR_SW_STATE_DB_CONNECTION'], 'projections', projID + 'PJ.JSON')
        # modvars.update(GB_get_db_json(env['AVENIR_SW_STATE_DB_CONNECTION'], 'projections', projID + 'AM.JSON'))
        # modvars.update(GB_get_db_json(env['AVENIR_SW_STATE_DB_CONNECTION'], 'projections', projID + 'DP.JSON'))
        # modvars.update(GB_get_db_json(env['AVENIR_SW_STATE_DB_CONNECTION'], 'projections', projID + 'FP.JSON'))
        # for mv in modvars:
        #     #print(mv) 
        #     if mv in ['<AM_ChildMortByCD4WithART0to6_V1>', '<AM_ChildMortByCD4WithART0to6Perc_V1>',
        #               '<AM_ChildMortByCD4WithART7to12_V1>', '<AM_ChildMortByCD4WithART7to12Perc_V1>',
        #               '<AM_ChildMortByCD4WithARTGT12_V1>', '<AM_ChildMortByCD4WithARTGT12Perc_V1>']:
        #         #print('meow')
        #         continue
        #     if type(modvars[mv]) == list:
        #             if len(modvars[mv])>0 and ((type(modvars[mv][0])==dict) or(type(modvars[mv][0])==str)) :
        #                 modvars[mv] = np.array(modvars[mv], order='C')#, dtype = dt)
        #             else:
        #                 modvars[mv] = np.array(modvars[mv], order='C', dtype=dt)#, dtype = dt)
        return modvars
    except Exception as e:
        extra_info = {'msg':e.args[0] if len(e.args)>0 else''}
        tb = traceback.format_exception(e)
        logger.error(extra_info)
        logger.error(tb)
        raise SpectrumException(GB_SW_BADGETMODVARS, extra_info=extra_info) 
    
def set_all_modvars(projID, projection):
    return set_calc_modvars(projID, projection)

def set_calc_modvars(projID, projection):
    try:
        modules = {}

        numpy_type = type(np.array([]))

        for tag in projection:
            # log(tag)
            if tag[0] == '<':
                mod_str = tag[1:3]
                if mod_str not in modules:
                    modules[mod_str] = []
                    
                if type(projection[tag]) == numpy_type:
                    projection[tag] = np.nan_to_num(projection[tag], copy=True, nan=0.0, posinf=None, neginf=None)
                    projection[tag] = projection[tag].tolist()
                    
                #print(tag)
                modules[mod_str].append({'tag':tag, 'value':projection[tag]})
            
        
        packet = {
            "projID": projID,
            "modules":  [{'module':mod_str, 'modvars':modules[mod_str]} for mod_str in modules] 
        }
        pass
        response = set_modvars(packet)
            
        if response.status_code!=200:
            raise Exception('Setmodvars filter api call failed')
        
        ######## By  MODULE ####################
        # for mod_str in modules:
        #     packet = {
        #         "projID": projID,
        #         "modules": [{'module':mod_str, 'modvars':modules[mod_str]}]
        #     }
        
        #     response = set_modvars(packet)
            
        #     if response.status_code!=200:
        #         raise Exception('Setmodvars filter api call failed')

        
        # ######## By  MODVAR ####################
        # for mod_str in modules:
        #     for mv in modules[mod_str]:
        #         packet = {
        #             "projID": projID,
        #             "modules": [{'module':mod_str, 'modvars':mv}]
        #         }
        #         print(mv['tag'])
        #         # if mv['tag'] == '<FP_RelativeRisks_V1>':
        #         #     print(mv['value'])
        #         if mv['tag'] != '<FP_RelativeRisks_V1>':
        #             response = set_modvars(packet)
                    
        #             if response.status_code!=200:
        #                 raise Exception('Setmodvars filter api call failed')
    
    except Exception as e:
        extra_info = {'msg':e.args[0] if len(e.args)>0 else''}
        tb = traceback.format_exception(e)
        logger.error(extra_info)
        logger.error(tb)
        raise SpectrumException(GB_SW_BADSETMODVARS, extra_info=extra_info) 