# Contains methods for setting up OHT ModVars

from os import environ

from AvenirCommon.Database import GB_get_db_json

import SpectrumCommon.Const.GB as gbc

import SpectrumCommon.Const.BG.BGConst as bgc
import SpectrumCommon.Const.BG.BGConstLink as bgcl
import SpectrumCommon.Const.BG.BGDatabaseKeys as bgdbk
import SpectrumCommon.Const.BG.BGTags as bgmvt
import SpectrumCommon.Modvars.BG.BGModVarUtil as bgmvu
import SpectrumCommon.Modvars.BG.BGModVarDefs as bgmvd
import SpectrumCommon.Util.BG.BGUtilLink as bgul

#######################################################################################################
#                                                                                                     #
#                                       Database loading methods                                      #
#                                                                                                     #
#######################################################################################################

#########################################   Inputs   ######################################################

def BG_load_budget_DB():
    budget_DB_file_name = bgc.BG_BUDGET_DB_NAME + '_' + bgc.BG_BUDGET_DB_CURR_VERSION + '.' + gbc.GB_JSON
    budget_DB = GB_get_db_json(environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_BG_CONTAINER, budget_DB_file_name)

    return budget_DB

def BG_load_budget_category_DB():
    budget_category_DB_file_name = bgc.BG_BUDGET_CAT_DB_NAME + '_' + bgc.BG_BUDGET_CAT_DB_CURR_VERSION + '.' + gbc.GB_JSON
    budget_category_DB = GB_get_db_json(environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_BG_CONTAINER, budget_category_DB_file_name)

    return budget_category_DB

def BG_load_indicator_mapping_DB():
    ind_mapping_DB_file_name = bgc.BG_INDICATOR_MAPPING_DB_NAME + '_' + bgc.BG_INDICATOR_MAPPING_DB_CURR_VERSION + '.' + gbc.GB_JSON
    ind_mapping_DB = GB_get_db_json(environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_BG_CONTAINER, ind_mapping_DB_file_name)

    return ind_mapping_DB

def BG_load_funding_framework_DB():
    funding_framework_DB_file_name = bgc.BG_FUND_FW_DB_NAME + '_' + bgc.BG_FUND_FW_DB_CURR_VERSION + '.' + gbc.GB_JSON
    funding_framework_DB = GB_get_db_json(environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_BG_CONTAINER, funding_framework_DB_file_name)

    return funding_framework_DB

def BG_load_funding_source_DB():
    funding_source_DB_file_name = bgc.BG_FUND_SOURCE_DB_NAME + '_' + bgc.BG_FUND_SOURCE_DB_CURR_VERSION + '.' + gbc.GB_JSON
    funding_source_DB = GB_get_db_json(environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_BG_CONTAINER, funding_source_DB_file_name)

    return funding_source_DB

#######################################################################################################
#                                                                                                     #
#                                       Budgets                                                       #
#                                                                                                     #
#######################################################################################################

def BG_init_budget_records(budget_DB, costing_mode, num_dynamic_staff_types = int, budget_ID = ''):
    budget_records = []

    for budget_DB_obj in budget_DB:
        if (budget_ID == '') or (budget_ID == str(budget_DB_obj[bgdbk.BG_ID_KEY_BDB])):
            if (((costing_mode == gbc.GB_IHT_COSTING_MODE) and (str(gbc.GB_IHT_COSTING_MODE) in budget_DB_obj[bgdbk.BG_COSTING_MODES_KEY_BDB])) or
                ((costing_mode == gbc.GB_TB_COSTING_MODE) and (str(gbc.GB_TB_COSTING_MODE) in budget_DB_obj[bgdbk.BG_COSTING_MODES_KEY_BDB]))):
                    budget_records.append(BG_init_budget_rec(budget_DB_obj, num_dynamic_staff_types))

    return budget_records

def BG_init_budget_rec(budget_DB_obj = dict, num_dynamic_staff_types = int):

    ID = str(budget_DB_obj[bgdbk.BG_ID_KEY_BDB]) 
    english_str = budget_DB_obj[bgdbk.BG_ENGLISH_STRING_KEY_BDB] 
    str_constant = budget_DB_obj[bgdbk.BG_STRING_CONSTANT_KEY_BDB] 

    budget_rec = bgmvd.BG_create_budget_rec(ID, english_str, str_constant, num_dynamic_staff_types)

    return budget_rec

#######################################################################################################
#                                                                                                     #
#                                       Budget categories                                             #
#                                                                                                     #
#######################################################################################################

def BG_init_budget_cat_records(budget_cat_DB, costing_mode, num_years = int, budget_ID = ''):
    budget_cat_records = []

    for budget_cat_DB_obj in budget_cat_DB:
        if (budget_ID == '') or (budget_ID == str(budget_cat_DB_obj[bgdbk.BG_BUDGET_ID_KEY_BCDB])):
            if (((costing_mode == gbc.GB_IHT_COSTING_MODE) and (str(gbc.GB_IHT_COSTING_MODE) in budget_cat_DB_obj[bgdbk.BG_COSTING_MODES_KEY_BCDB])) or
                ((costing_mode == gbc.GB_TB_COSTING_MODE) and (str(gbc.GB_TB_COSTING_MODE) in budget_cat_DB_obj[bgdbk.BG_COSTING_MODES_KEY_BCDB]))):
                    budget_cat_records.append(BG_init_budget_cat_rec(budget_cat_DB_obj, num_years))

    return budget_cat_records

def BG_init_budget_cat_rec(budget_cat_DB_obj, num_years = int):

    budget_ID = str(budget_cat_DB_obj[bgdbk.BG_BUDGET_ID_KEY_BCDB]) 
    budget_cat_ID = str(budget_cat_DB_obj[bgdbk.BG_ID_KEY_BCDB]) 
    english_str = budget_cat_DB_obj[bgdbk.BG_ENGLISH_STRING_KEY_BCDB] 
    str_constant = budget_cat_DB_obj[bgdbk.BG_STRING_CONSTANT_KEY_BCDB] 

    budget_cat_rec = bgmvd.BG_create_budget_category_rec(budget_ID, budget_cat_ID, english_str, str_constant, num_years)

    return budget_cat_rec

#######################################################################################################
#                                                                                                     #
#                                       Indicator mappings                                            #
#                                                                                                     #
#######################################################################################################

def BG_set_default_indicator_mappings(ind_mapping_DB, required_mod_vars, costing_mode, budget_ID):
    '''
        This method will initialize everything related to budgets rather than just the budget records themselves.

            Parameters:
                ind_mapping_DB (dict): Database of budget category mappings for all indicators.

                required_mod_vars (dict): MV tag, MV value pairs of all MVs required to execute this function.  The following MVs are required:

                    BG_INDICATOR_RECORDS_IC_TAG  
                    BG_INDICATOR_RECORDS_PC_TAG        
                    BG_INDICATOR_RECORDS_IS_TAG   

                    IH_DELIV_CHAN_RECORDS_TAG_V1
                    IH_PROG_AREA_RECORDS_TAG_V1

                budget_ID (str) : budget ID.
              
            Returns:
                Nothing.
    '''

    ind_records_IC_mv = required_mod_vars[bgmvt.BG_INDICATOR_RECORDS_IC_TAG]
    ind_records_PC_mv = required_mod_vars[bgmvt.BG_INDICATOR_RECORDS_PC_TAG]
    ind_records_IS_mv = required_mod_vars[bgmvt.BG_INDICATOR_RECORDS_IS_TAG]

    deliv_chan_records_mv = required_mod_vars[bgcl.BG_IH_DELIV_CHAN_RECORDS_TAG]
    prog_area_records_mv = required_mod_vars[bgcl.BG_IH_PROG_AREA_RECORDS_TAG]

    def map_PC_rec(ind_mapping_obj_l, prog_area_ID):
        ind_rec = bgmvu.get_BG_ind_record_PC(
            ind_records_PC_mv, budget_ID, int(ind_mapping_obj_l[bgdbk.BG_IND_TYPE_IDS_KEY_IMDB][0]), 
            prog_area_ID,
            str(ind_mapping_obj_l[bgdbk.BG_COSTING_SECT_ID_KEY_IMDB]), 
            str(ind_mapping_obj_l[bgdbk.BG_COSTING_SUBSECT_ID_KEY_IMDB]), 
            str(ind_mapping_obj_l[bgdbk.BG_ACTIVITY_ID_KEY_IMDB])
        )

        if ind_rec != gbc.GB_NOT_FOUND: 
            bgmvu.set_BG_ind_budget_cat_ID(ind_rec, str(ind_mapping_obj_l[bgdbk.BG_BUDGET_CAT_ID_KEY_IMDB]))

    for ind_mapping_obj in ind_mapping_DB:

        if (budget_ID == '') or (budget_ID == str(ind_mapping_obj[bgdbk.BG_BUDGET_ID_KEY_IMDB])):

            if (((costing_mode == gbc.GB_IHT_COSTING_MODE) and (str(gbc.GB_IHT_COSTING_MODE) in ind_mapping_obj[bgdbk.BG_COSTING_MODES_KEY_IMDB])) or
                ((costing_mode == gbc.GB_TB_COSTING_MODE) and (str(gbc.GB_TB_COSTING_MODE) in ind_mapping_obj[bgdbk.BG_COSTING_MODES_KEY_IMDB]))):
                    
                    if ind_mapping_obj[bgdbk.BG_MOD_ID_KEY_IMDB] == gbc.GB_PC:
                        if costing_mode == gbc.GB_IHT_COSTING_MODE:
                            for prog_area_rec in prog_area_records_mv:
                                prog_area_ID = bgul.BG_get_IH_prog_area_ID(prog_area_rec)

                                map_PC_rec(ind_mapping_obj, prog_area_ID)

                        elif costing_mode == gbc.GB_TB_COSTING_MODE:
                             
                            map_PC_rec(ind_mapping_obj, str(gbc.GB_NOT_FOUND))

                    elif ind_mapping_obj[bgdbk.BG_MOD_ID_KEY_IMDB] == gbc.GB_IC:
                        # Database currently assumes all values are repeated for all delivery channels.
                        for deliv_chan_rec in deliv_chan_records_mv:
                            deliv_chan_ID = bgul.BG_get_IH_deliv_chan_ID(deliv_chan_rec)

                            for ind_type_ID in ind_mapping_obj[bgdbk.BG_IND_TYPE_IDS_KEY_IMDB]:
                                ind_rec = bgmvu.get_BG_ind_record_IC_deliv_chan(ind_records_IC_mv, budget_ID, int(ind_type_ID), str(ind_mapping_obj[bgdbk.BG_IND_ID_KEY_IMDB]), False, deliv_chan_ID)

                                if ind_rec != gbc.GB_NOT_FOUND: 
                                    bgmvu.set_BG_ind_budget_cat_ID(ind_rec, str(ind_mapping_obj[bgdbk.BG_BUDGET_CAT_ID_KEY_IMDB]))

                        # All delivery channels combined.
                        for ind_type_ID in ind_mapping_obj[bgdbk.BG_IND_TYPE_IDS_KEY_IMDB]:
                            ind_rec = bgmvu.get_BG_ind_record_IC_deliv_chan(ind_records_IC_mv, budget_ID, int(ind_type_ID), str(ind_mapping_obj[bgdbk.BG_IND_ID_KEY_IMDB]), False, str(gbc.GB_NOT_FOUND))
                            
                            if ind_rec != gbc.GB_NOT_FOUND: 
                                bgmvu.set_BG_ind_budget_cat_ID(ind_rec, str(ind_mapping_obj[bgdbk.BG_BUDGET_CAT_ID_KEY_IMDB]))

                    elif ind_mapping_obj[bgdbk.BG_MOD_ID_KEY_IMDB] == gbc.GB_IS:
                        # Currently, only TB Costing mode has default budget category mappings, so we can use "-1" for the prog area.
                        ind_rec = bgmvu.get_BG_ind_record_IS_non_prog_mgmt(
                            ind_records_IS_mv, budget_ID, int(ind_mapping_obj[bgdbk.BG_IND_TYPE_IDS_KEY_IMDB][0]), str(ind_mapping_obj[bgdbk.BG_IND_ID_KEY_IMDB]), str(gbc.GB_NOT_FOUND)
                        )

                        if ind_rec != gbc.GB_NOT_FOUND: 
                            bgmvu.set_BG_ind_budget_cat_ID(ind_rec, str(ind_mapping_obj[bgdbk.BG_BUDGET_CAT_ID_KEY_IMDB]))

#######################################################################################################
#                                                                                                     #
#                                       Funding frameworks                                            #
#                                                                                                     #
#######################################################################################################

def BG_init_fund_framework_records(fund_framework_DB, costing_mode, fund_framework_ID = ''):
    fund_framework_records = []

    for fund_framework_DB_obj in fund_framework_DB:
        if (fund_framework_ID == '') or (fund_framework_ID == str(fund_framework_DB_obj[bgdbk.BG_ID_KEY_FFWDB])):
            if (((costing_mode == gbc.GB_IHT_COSTING_MODE) and (str(gbc.GB_IHT_COSTING_MODE) in fund_framework_DB_obj[bgdbk.BG_COSTING_MODES_KEY_FFWDB])) or
                ((costing_mode == gbc.GB_TB_COSTING_MODE) and (str(gbc.GB_TB_COSTING_MODE) in fund_framework_DB_obj[bgdbk.BG_COSTING_MODES_KEY_FFWDB]))):
                    fund_framework_records.append(BG_init_fund_framework_rec(fund_framework_DB_obj))

    return fund_framework_records

def BG_init_fund_framework_rec(fund_framework_DB_obj):

    ID = str(fund_framework_DB_obj[bgdbk.BG_ID_KEY_FFWDB]) 
    english_str = fund_framework_DB_obj[bgdbk.BG_ENGLISH_STRING_KEY_FFWDB] 
    str_constant = fund_framework_DB_obj[bgdbk.BG_STRING_CONSTANT_KEY_FFWDB] 

    fund_framework_rec = bgmvd.BG_create_funding_framework_rec(ID, english_str, str_constant)

    return fund_framework_rec

#######################################################################################################
#                                                                                                     #
#                                       Funding sources                                               #
#                                                                                                     #
#######################################################################################################

def BG_init_fund_source_records(fund_source_DB, costing_mode, fund_framework_ID = ''):
    fund_source_records = []

    for fund_source_DB_obj in fund_source_DB:
        if (fund_framework_ID == '') or (fund_framework_ID == str(fund_source_DB_obj[bgdbk.BG_FUND_FW_ID_KEY_FSDB])):
            if (((costing_mode == gbc.GB_IHT_COSTING_MODE) and (str(gbc.GB_IHT_COSTING_MODE) in fund_source_DB_obj[bgdbk.BG_COSTING_MODES_KEY_FSDB])) or
                ((costing_mode == gbc.GB_TB_COSTING_MODE) and (str(gbc.GB_TB_COSTING_MODE) in fund_source_DB_obj[bgdbk.BG_COSTING_MODES_KEY_FSDB]))):
                    fund_source_records.append(BG_init_fund_source_rec(fund_source_DB_obj))

    return fund_source_records

def BG_init_fund_source_rec(fund_source_DB_obj):

    fund_framework_ID = str(fund_source_DB_obj[bgdbk.BG_FUND_FW_ID_KEY_FSDB]) 
    fund_source_ID = str(fund_source_DB_obj[bgdbk.BG_ID_KEY_FSDB]) 
    english_str = fund_source_DB_obj[bgdbk.BG_ENGLISH_STRING_KEY_FSDB] 
    str_constant = fund_source_DB_obj[bgdbk.BG_STRING_CONSTANT_KEY_FSDB] 

    found_source_rec = bgmvd.BG_create_funding_source_rec(fund_framework_ID, fund_source_ID, english_str, str_constant)

    return found_source_rec

########################################################################################################################################
########################################################################################################################################
#                                                                                                                                      #
#                                                       Meta data                                                                      #
#                                                                                                                                      #
########################################################################################################################################
########################################################################################################################################

def BG_init_default_budget_list_meta(budget_DB, costing_mode):
    default_budget_list_meta = []

    for budget_DB_obj in budget_DB:
        if (((costing_mode == gbc.GB_IHT_COSTING_MODE) and (str(gbc.GB_IHT_COSTING_MODE) in budget_DB_obj[bgdbk.BG_COSTING_MODES_KEY_BDB])) or
            ((costing_mode == gbc.GB_TB_COSTING_MODE) and (str(gbc.GB_TB_COSTING_MODE) in budget_DB_obj[bgdbk.BG_COSTING_MODES_KEY_BDB]))):
                default_budget_list_meta.append({
                    'mstID'          : str(budget_DB_obj[bgdbk.BG_ID_KEY_BDB]),
                    'name'           : budget_DB_obj[bgdbk.BG_ENGLISH_STRING_KEY_BDB],
                    'stringConstant' : budget_DB_obj[bgdbk.BG_STRING_CONSTANT_KEY_BDB]
                })
    
    return default_budget_list_meta

def BG_init_default_fund_framework_list_meta(fund_fw_DB, costing_mode):
    default_fund_fw_list_meta = []

    for fund_fw_DB_obj in fund_fw_DB:
        if (((costing_mode == gbc.GB_IHT_COSTING_MODE) and (str(gbc.GB_IHT_COSTING_MODE) in fund_fw_DB_obj[bgdbk.BG_COSTING_MODES_KEY_FFWDB])) or
            ((costing_mode == gbc.GB_TB_COSTING_MODE) and (str(gbc.GB_TB_COSTING_MODE) in fund_fw_DB_obj[bgdbk.BG_COSTING_MODES_KEY_FFWDB]))):
                default_fund_fw_list_meta.append({
                    'mstID'          : str(fund_fw_DB_obj[bgdbk.BG_ID_KEY_FFWDB]),
                    'name'           : fund_fw_DB_obj[bgdbk.BG_ENGLISH_STRING_KEY_FFWDB],
                    'stringConstant' : fund_fw_DB_obj[bgdbk.BG_STRING_CONSTANT_KEY_FFWDB]
                })
    
    return default_fund_fw_list_meta

