# Contains methods for setting up OHT ModVars

from copy import deepcopy
import numpy as np
from os import environ

import AvenirCommon.Util as acu
from AvenirCommon.Database import GB_get_db_json

import SpectrumCommon.Const.GB as gbc

import SpectrumCommon.Const.IC.ICConst as icc
import SpectrumCommon.Const.IC.ICTargetPopulationIDs as ictpi
import SpectrumCommon.Const.IC.ICConstLink as iccl
import SpectrumCommon.Const.IC.ICDatabaseConst as icdbc
import SpectrumCommon.Const.IC.ICModVarFields as icmvf
import SpectrumCommon.Modvars.IC.ICModVarUtil as icmvu
import SpectrumCommon.Modvars.IC.ICModVarDefs as icmvd

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

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


def IC_load_drug_supply_DB():
    drug_supply_DB_file_name = icc.IC_DRUG_SUPPLY_DB_NAME + "_" + icc.IC_DRUG_SUPPLY_DB_CURR_VERSION + "." + gbc.GB_JSON
    drug_supply_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, drug_supply_DB_file_name
    )

    return drug_supply_DB


def IC_load_intervention_DB(costing_mode=int):
    environment = environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV]

    intervention_DB = []
    intervention_DB_IHT_ID_info_only = None

    if costing_mode == gbc.GB_IHT_COSTING_MODE:
        intervention_DB_file_name = (
            iccl.IC_IV_INTERVENTION_DB_NAME + "_OH_" + iccl.IC_IV_IH_INTERVENTION_DB_CURR_VERSION + "." + gbc.GB_JSON
        )
        intervention_DB = GB_get_db_json(environment, gbc.GB_IH_CORE_CONTAINER, intervention_DB_file_name)

    # If costing mode was not specified, assume IHT since that is Intervention Costing's main purpose for existing.
    elif costing_mode == gbc.GB_TB_COSTING_MODE:
        intervention_DB_file_name = (
            iccl.IC_IV_INTERVENTION_DB_NAME + "_TI_" + iccl.IC_IV_TI_INTERVENTION_DB_CURR_VERSION + "." + gbc.GB_JSON
        )
        intervention_DB = GB_get_db_json(environment, gbc.GB_IH_CORE_CONTAINER, intervention_DB_file_name)

        # If TB costing is on, we'll need access to the IHT interventions well, because the user is allowed to move IHT interventions into TB.
        intervention_DB_file_name_IHT_ID_info_only = (
            iccl.IC_IV_INTERVENTION_DB_NAME + "_OH_" + iccl.IC_IV_IH_INTERVENTION_DB_CURR_VERSION + "." + gbc.GB_JSON
        )
        intervention_DB_IHT_ID_info_only = GB_get_db_json(
            environment, gbc.GB_IH_CORE_CONTAINER, intervention_DB_file_name_IHT_ID_info_only
        )

    elif costing_mode == gbc.GB_LIST_COSTING_MODE:
        intervention_DB_file_name = (
            iccl.IC_IV_INTERVENTION_DB_NAME + "_" + iccl.IC_IV_CS_INTERVENTION_DB_CURR_VERSION + "." + gbc.GB_JSON
        )
        intervention_DB = GB_get_db_json(environment, gbc.GB_CS_CONTAINER, intervention_DB_file_name)

    return intervention_DB, intervention_DB_IHT_ID_info_only


def IC_load_PIN_DB(country_ID):
    PIN_DB_file_name = (
        icc.IC_PIN_DB_DIR.replace("\\", "/") + "/" + country_ID + "_" + icc.IC_PIN_DB_CURR_VERSION + "." + gbc.GB_JSON
    )
    PIN_DB = GB_get_db_json(environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, PIN_DB_file_name)

    return PIN_DB


def IC_load_PIN_by_year_DB(country_ID):
    PIN_by_year_DB_file_name = (
        icc.IC_PIN_BY_YEAR_DB_DIR.replace("\\", "/")
        + "/"
        + country_ID
        + "_"
        + icc.IC_PIN_BY_YEAR_DB_CURR_VERSION
        + "."
        + gbc.GB_JSON
    )
    PIN_by_year_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, PIN_by_year_DB_file_name
    )

    return PIN_by_year_DB


def IC_load_non_impact_coverage_DB(country_ID):
    non_impact_coverage_DB_file_name = (
        icc.IC_NON_IMPACT_COVERAGE_DB_DIR.replace("\\", "/")
        + "/"
        + country_ID
        + "_"
        + icc.IC_NON_IMPACT_COVERAGE_DB_CURR_VERSION
        + "."
        + gbc.GB_JSON
    )
    non_impact_coverage_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, non_impact_coverage_DB_file_name
    )

    return non_impact_coverage_DB


def IC_load_non_impact_coverage_by_year_DB():
    pass
    # There are currently no more interventions to be read in here. Leave as placeholder in case this type comes back.
    # non_impact_coverage_by_year_DB_file_name = icc.IC_NON_IMPACT_COVERAGE_BY_YEAR_DB_DIR.replace('\\', '/') + '/' + countryID + '_' + icc.IC_NON_IMPACT_COVERAGE_BY_YEAR_DB_CURR_VERSION + '.' + gbc.GB_JSON
    # non_impact_coverage_by_year_DB = GB_get_db_json(environment, gbc.GB_IC_CONTAINER, non_impact_coverage_by_year_DB_file_name)


def IC_load_targ_pop_direct_entry_DB(country_ID):
    targ_pop_direct_entry_DB_file_name = (
        icc.IC_TARG_POP_DIRECT_ENTRY_DB_DIR.replace("\\", "/")
        + "/"
        + country_ID
        + "_"
        + icc.IC_TARG_POP_DIRECT_ENTRY_DB_CURR_VERSION
        + "."
        + gbc.GB_JSON
    )
    targ_pop_direct_entry_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, targ_pop_direct_entry_DB_file_name
    )

    return targ_pop_direct_entry_DB


def IC_load_targ_pop_DB():
    targ_pop_DB_file_name = icc.IC_TARG_POP_DB_NAME + "_" + icc.IC_TARG_POP_DB_CURR_VERSION + "." + gbc.GB_JSON
    targ_pop_DB = GB_get_db_json(environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, targ_pop_DB_file_name)

    return targ_pop_DB


def IC_load_treatment_input_group_DB():
    treatment_input_group_DB_file_name = (
        icc.IC_TREATMENT_INPUT_GROUP_DB_NAME + "_" + icc.IC_TREATMENT_INPUT_DB_CURR_VERSION + "." + gbc.GB_JSON
    )
    treatment_input_group_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, treatment_input_group_DB_file_name
    )

    return treatment_input_group_DB


def IC_load_treatment_input_DB():
    treatment_input_DB_file_name = (
        icc.IC_TREATMENT_INPUT_DB_NAME + "_" + icc.IC_TREATMENT_INPUT_DB_CURR_VERSION + "." + gbc.GB_JSON
    )
    treatment_input_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, treatment_input_DB_file_name
    )

    return treatment_input_DB


###################################   LiST Costing databases   ##################################


def IC_load_health_system_costs_CS_DB(country_ID):
    health_system_costs_DB_file_name = (
        icc.IC_HEALTH_SYSTEM_COSTS_DB_DIR.replace("\\", "/")
        + "/"
        + country_ID
        + "_"
        + icc.IC_HEALTH_SYSTEM_COSTS_DB_CURR_VERSION
        + "."
        + gbc.GB_JSON
    )
    health_system_costs_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, health_system_costs_DB_file_name
    )

    return health_system_costs_DB


def IC_load_outpat_visit_inpat_day_costs_CS_DB(country_ID):
    outpat_visit_inpat_day_DB_file_name = (
        icc.IC_OUTPAT_VISIT_INPAT_DAY_COSTS_CS_DB_DIR.replace("\\", "/")
        + "/"
        + country_ID
        + "_"
        + icc.IC_OUTPAT_VISIT_INPAT_DAY_COSTS_CS_DB_CURR_VERSION
        + "."
        + gbc.GB_JSON
    )
    outpat_visit_inpat_day_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, outpat_visit_inpat_day_DB_file_name
    )

    return outpat_visit_inpat_day_DB


def IC_load_outpat_visit_inpat_day_costs_TB_DB(country_ID):
    outpat_visit_inpat_day_DB_file_name = (
        icc.IC_OUTPAT_VISIT_INPAT_DAY_COSTS_TB_DB_DIR.replace("\\", "/")
        + "/"
        + country_ID
        + "_"
        + icc.IC_OUTPAT_VISIT_INPAT_DAY_COSTS_TB_DB_CURR_VERSION
        + "."
        + gbc.GB_JSON
    )
    outpat_visit_inpat_day_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, outpat_visit_inpat_day_DB_file_name
    )

    return outpat_visit_inpat_day_DB


###################################   Pre-results / Calculated - These databases are made in ICProj   ##################################


def IC_load_drug_cost_per_avg_case_DB(costing_mode):
    drug_cost_per_avg_case_DB_file_name = (
        icc.IC_DRUG_COST_PER_AVG_CASE_DB_NAME + "_" + icc.IC_DRUG_COST_PER_AVG_CASE_DB_CURR_VERSION + "." + gbc.GB_JSON
    )

    if costing_mode == gbc.GB_TB_COSTING_MODE:
        drug_cost_per_avg_case_DB_file_name = "TI_" + drug_cost_per_avg_case_DB_file_name

    elif costing_mode == gbc.GB_LIST_COSTING_MODE:
        drug_cost_per_avg_case_DB_file_name = "CS_" + drug_cost_per_avg_case_DB_file_name

    drug_cost_per_avg_case_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, drug_cost_per_avg_case_DB_file_name
    )

    return drug_cost_per_avg_case_DB


def IC_load_supply_cost_per_avg_case_DB(costing_mode):
    supply_cost_per_avg_case_DB_file_name = (
        icc.IC_SUPPLY_COST_PER_AVG_CASE_DB_NAME
        + "_"
        + icc.IC_SUPPLY_COST_PER_AVG_CASE_DB_CURR_VERSION
        + "."
        + gbc.GB_JSON
    )

    if costing_mode == gbc.GB_TB_COSTING_MODE:
        supply_cost_per_avg_case_DB_file_name = "TI_" + supply_cost_per_avg_case_DB_file_name

    elif costing_mode == gbc.GB_LIST_COSTING_MODE:
        supply_cost_per_avg_case_DB_file_name = "CS_" + supply_cost_per_avg_case_DB_file_name

    supply_cost_per_avg_case_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, supply_cost_per_avg_case_DB_file_name
    )

    return supply_cost_per_avg_case_DB


def IC_load_med_personnel_min_per_avg_case_DB(costing_mode):
    med_personnel_min_per_avg_case_DB_file_name = (
        icc.IC_MED_PERSONNEL_MIN_PER_AVG_CASE_DB_NAME
        + "_"
        + icc.IC_MED_PERSONNEL_MIN_PER_AVG_CASE_DB_CURR_VERSION
        + "."
        + gbc.GB_JSON
    )

    if costing_mode == gbc.GB_TB_COSTING_MODE:
        med_personnel_min_per_avg_case_DB_file_name = "TI_" + med_personnel_min_per_avg_case_DB_file_name

    elif costing_mode == gbc.GB_LIST_COSTING_MODE:
        med_personnel_min_per_avg_case_DB_file_name = "CS_" + med_personnel_min_per_avg_case_DB_file_name

    med_personnel_min_per_avg_case_DB = GB_get_db_json(
        environ[gbc.GB_SPECT_MOD_DATA_CONN_ENV], gbc.GB_IC_CONTAINER, med_personnel_min_per_avg_case_DB_file_name
    )

    return med_personnel_min_per_avg_case_DB


#######################################################################################################
#                                                                                                     #
#                                       Target populations                                            #
#                                                                                                     #
#######################################################################################################

#######################################################################################################
#                                                                                                     #
#                                       Interventions                                                 #
#                                                                                                     #
#######################################################################################################


def IC_init_interv_rec(interv_DB_obj, targ_pop_records, active_modules, num_years=int, costing_mode=int):

    interv_ID = str(interv_DB_obj[iccl.IC_IV_MST_ID_KEY_IDB])
    english_str = interv_DB_obj[iccl.IC_IV_ENGLISH_STRING_KEY_IH_IDB]
    str_constant = interv_DB_obj[iccl.IC_IV_STRING_CONSTANT_KEY_IH_IDB]
    if costing_mode == gbc.GB_LIST_COSTING_MODE:
        active = False
    else:
        active = True
    impact_interv = interv_DB_obj[iccl.IC_IV_INTERV_IMPACT_KEY_IDB]
    prog_area_mst_ID = str(interv_DB_obj[iccl.IC_IV_GROUP_MST_ID_KEY_IH_IDB])
    subgroup_mstID = str(interv_DB_obj[iccl.IC_IV_SUBGROUP_MST_ID_KEY_IH_IDB])
    targ_pop_mst_ID = interv_DB_obj[iccl.IV_TARG_POP_MST_ID_KEY_IDB]

    num_costed_deliv_chans = 0
    if costing_mode == gbc.GB_LIST_COSTING_MODE:
        num_costed_deliv_chans = iccl.IC_IH_NUM_DEFAULT_DELIV_CHANS_COSTED_CS
    else:
        num_costed_deliv_chans = iccl.IC_IH_NUM_DEFAULT_DELIV_CHANS_COSTED

    interv_rec = icmvd.IC_create_interv_rec(
        interv_ID,
        english_str,
        str_constant,
        active,
        impact_interv,
        prog_area_mst_ID,
        subgroup_mstID,
        num_costed_deliv_chans + icc.IC_NUM_DELIV_CHANS,
        num_years,
    )

    for value in interv_DB_obj[iccl.IC_IV_SPECIAL_CASES_IH_KEY_IDB]:
        icmvu.add_IC_interv_special_case(interv_rec, value)

    # The targ pop editor only allows a select group of target populations to be shown as choices for interventions.
    # If the intervention's default target population is not in the set, change it to be Total population.
    if targ_pop_mst_ID is None:
        targ_pop_mst_ID = ictpi.IC_TP_TOTAL_POPULATION_MST_ID

    targ_pop_rec = icmvu.get_IC_def_targ_pop_rec(targ_pop_records, targ_pop_mst_ID)

    if ((icmvu.get_IC_def_targ_pop_req_mod(targ_pop_rec, str(gbc.GB_TB))) and (gbc.GB_TB not in active_modules)) or (
        (icmvu.get_IC_def_targ_pop_req_mod(targ_pop_rec, str(gbc.GB_CS))) and (gbc.GB_CS not in active_modules)
    ):
        targ_pop_mst_ID = ictpi.IC_TP_TOTAL_POPULATION_MST_ID

    if icmvu.get_IC_def_targ_pop_applic_prog_area(targ_pop_rec, prog_area_mst_ID):
        icmvu.set_IC_interv_targ_pop_mst_ID(interv_rec, targ_pop_mst_ID)
    else:
        icmvu.set_IC_interv_targ_pop_mst_ID(interv_rec, ictpi.IC_TP_TOTAL_POPULATION_MST_ID)

    icmvu.set_IC_interv_PIN_string_constant(interv_rec, interv_DB_obj[iccl.IV_PIN_STRING_CONSTANT_KEY_IDB])

    # Delivery channels in the database are the IHT/TB ones, so we basically have to map the IHT ones to the LiST ones.
    if costing_mode == gbc.GB_LIST_COSTING_MODE:
        for yr in acu.GBRange(icc.IC_CURRENT_YEAR, icc.IC_TARGET_YEAR):
            # Costed
            icmvu.set_IC_interv_perc_deliv(
                interv_rec,
                iccl.IC_IH_COMMUNITY_CHAN_CURR_ID_CS,
                yr,
                interv_DB_obj[iccl.IC_IV_PERC_DELIV_KEY_IDB][iccl.IC_IH_COMMUNITY_CHAN_CURR_ID - 1][yr - 1],
            )

            icmvu.set_IC_interv_perc_deliv(
                interv_rec,
                iccl.IC_IH_OUTREACH_CHAN_CURR_ID_CS,
                yr,
                interv_DB_obj[iccl.IC_IV_PERC_DELIV_KEY_IDB][iccl.IC_IH_OUTREACH_CHAN_CURR_ID - 1][yr - 1],
            )

            icmvu.set_IC_interv_perc_deliv(
                interv_rec,
                iccl.IC_IH_CLINICAL_CURR_ID_CS,
                yr,
                interv_DB_obj[iccl.IC_IV_PERC_DELIV_KEY_IDB][iccl.IC_IH_GEN_OUTPATIENT_SERV_CHAN_CURR_ID - 1][yr - 1],
            )

            icmvu.set_IC_interv_perc_deliv(
                interv_rec,
                iccl.IC_IH_HOSPITAL_CHAN_CURR_ID_CS,
                yr,
                interv_DB_obj[iccl.IC_IV_PERC_DELIV_KEY_IDB][iccl.IC_IH_FIRST_REFERRAL_CHAN_CURR_ID - 1][yr - 1],
            )

            # Non-costed
            icmvu.set_IC_interv_perc_deliv(
                interv_rec,
                iccl.IC_IH_HOSPITAL_CHAN_CURR_ID_CS + icc.IC_WASH_CHAN_CURR_ID,
                yr,
                interv_DB_obj[iccl.IC_IV_PERC_DELIV_KEY_IDB][
                    iccl.IC_IH_NUM_DEFAULT_DELIV_CHANS_COSTED + icc.IC_WASH_CHAN_CURR_ID - 1
                ][yr - 1],
            )

            icmvu.set_IC_interv_perc_deliv(
                interv_rec,
                iccl.IC_IH_HOSPITAL_CHAN_CURR_ID_CS + icc.IC_OTHER_NON_HEALTH_CHAN_CURR_ID,
                yr,
                interv_DB_obj[iccl.IC_IV_PERC_DELIV_KEY_IDB][
                    iccl.IC_IH_NUM_DEFAULT_DELIV_CHANS_COSTED + icc.IC_OTHER_NON_HEALTH_CHAN_CURR_ID - 1
                ][yr - 1],
            )

            icmvu.set_IC_interv_perc_deliv(
                interv_rec,
                iccl.IC_IH_HOSPITAL_CHAN_CURR_ID_CS + icc.IC_PRIVATE_SECTOR_CHAN_CURR_ID,
                yr,
                interv_DB_obj[iccl.IC_IV_PERC_DELIV_KEY_IDB][
                    iccl.IC_IH_NUM_DEFAULT_DELIV_CHANS_COSTED + icc.IC_PRIVATE_SECTOR_CHAN_CURR_ID - 1
                ][yr - 1],
            )
    else:
        for dc in acu.GBRange(
            iccl.IC_IH_COMMUNITY_CHAN_CURR_ID, iccl.IC_IH_NUM_DEFAULT_DELIV_CHANS_COSTED + icc.IC_NUM_DELIV_CHANS
        ):
            for yr in acu.GBRange(icc.IC_CURRENT_YEAR, icc.IC_TARGET_YEAR):
                icmvu.set_IC_interv_perc_deliv(
                    interv_rec, dc, yr, interv_DB_obj[iccl.IC_IV_PERC_DELIV_KEY_IDB][dc - 1][yr - 1]
                )

    return interv_rec


def IC_init_interv_records(intervention_DB, targ_pop_records, active_modules, num_years=int, costing_mode=int):
    interv_records = []

    for interv_DB_obj in intervention_DB:
        rec = IC_init_interv_rec(interv_DB_obj, targ_pop_records, active_modules, num_years, costing_mode)
        if rec["name"]:
            interv_records.append(rec)

    return interv_records


# Initializes a list of intervention records containing only enough info to identify and display the interventions in a list. Used for TB Costing to allow
# the users to pick IHT interventions and transfer them to TB standalone app.
def IC_init_interv_records_ID_info_only(intervention_DB, excluded_prog_area_ID):
    interv_records = []

    for interv_DB_obj in intervention_DB:
        prog_area_mst_ID = str(interv_DB_obj[iccl.IC_IV_GROUP_MST_ID_KEY_IH_IDB])

        if prog_area_mst_ID != excluded_prog_area_ID:
            mstID = str(interv_DB_obj[iccl.IC_IV_MST_ID_KEY_IDB])
            english_str = interv_DB_obj[iccl.IC_IV_ENGLISH_STRING_KEY_IH_IDB]
            str_constant = interv_DB_obj[iccl.IC_IV_STRING_CONSTANT_KEY_IH_IDB]
            subgroup_mstID = str(interv_DB_obj[iccl.IC_IV_SUBGROUP_MST_ID_KEY_IH_IDB])

            interv_rec = icmvd.IC_create_interv_rec_ID_info_only(
                mstID, english_str, str_constant, prog_area_mst_ID, subgroup_mstID
            )

            interv_records.append(interv_rec)

    return interv_records


def IC_set_interv_PIN(interv_dict, PIN_DB_obj, num_years):
    """
    Most interventions have one column of data, but a handful have
    their target populations and population in need values
    disaggregated by age group. Use the target population to
    determine how many columns we should be reading in for this
    intervention. We should have the target population from reading
    in the Interventions database at this point. *)
    """

    if type(interv_dict) is dict:
        targ_pop_mstID = icmvu.get_IC_interv_targ_pop_mst_ID(interv_dict)

        # Skip over special cases by age group for now. We'll cross that bridge later.
        # if not (
        #     (targ_pop_mstID == icc.IC_TP_AGE_GROUP_SET_1_MST_ID)
        #     or (targ_pop_mstID == icc.IC_TP_AGE_GROUP_SET_2_MST_ID)
        #     or (targ_pop_mstID == icc.IC_TP_FEMALES_BREAST_CANCER_MST_ID)
        #     or (targ_pop_mstID == icc.IC_MstWomenCervicalCancerDetS1)
        # ):
        pop_in_need = PIN_DB_obj[icdbc.IC_PIN_KEY_PINDB]

        if not isinstance(pop_in_need, list):
            for t in acu.GBRange(1, num_years):
                icmvu.set_IC_interv_PIN(interv_dict, t - 1, pop_in_need)

        # else:
        #    log(str(targ_pop_mstID))


def IC_set_intervs_PIN(interv_records, PIN_DB, num_years):

    for PIN_DB_obj in PIN_DB[icdbc.IC_INTERVENTION_LIST_KEY_PINDB]:
        interv_mstID = str(PIN_DB_obj[icdbc.IC_INTERV_MST_ID_KEY_PINDB])
        interv_dict = icmvu.get_IC_interv_rec(interv_records, interv_mstID)

        IC_set_interv_PIN(interv_dict, PIN_DB_obj, num_years)

    return interv_records


def IC_set_interv_PIN_by_year(interv_dict, PIN_by_year_DB_obj, num_years):
    pass


def IC_set_intervs_PIN_by_year(interv_records, PIN_by_year_DB, num_years):

    return interv_records


def IC_set_interv_non_impact_coverage(interv_rec, non_impact_coverage_DB_obj, num_years, costing_mode):

    if type(interv_rec) is dict:
        cov = non_impact_coverage_DB_obj[icdbc.IC_NON_IMPACT_COV_KEY_NICDB]
        interv_prog_area_ID = icmvu.get_IC_interv_prog_area_ID(interv_rec)

        for t in acu.GBRange(1, num_years):
            # Rachel said to set the coverages for NTD and NCD programme areas to 0 (shrug).
            if (costing_mode == gbc.GB_IHT_COSTING_MODE) and (
                (interv_prog_area_ID == str(iccl.IC_IH_NCD_MST_ID)) or (interv_prog_area_ID == str(iccl.IH_NTD_MST_ID))
            ):
                icmvu.set_IC_interv_coverage(interv_rec, t - 1, 0.0)
            else:
                icmvu.set_IC_interv_coverage(interv_rec, t - 1, cov)


def IC_set_intervs_non_impact_coverage(interv_records, non_impact_coverage_DB, num_years, costing_mode):

    for non_impact_coverage_DB_obj in non_impact_coverage_DB[icdbc.IC_INTERVENTION_LIST_KEY_NICDB]:
        interv_mst_ID = str(non_impact_coverage_DB_obj[icdbc.IC_INTERV_MST_ID_KEY_NICDB])
        interv_rec = icmvu.get_IC_interv_rec(interv_records, interv_mst_ID)

        IC_set_interv_non_impact_coverage(interv_rec, non_impact_coverage_DB_obj, num_years, costing_mode)

    return interv_records


def IC_set_interv_non_impact_coverage_by_year(interv_records, non_impact_coverage_by_year_DB, num_total_years):

    return interv_records


def IC_set_interv_targ_pop_direct_entry(interv_dict, targ_pop_direct_entry_DB_obj):

    pass


def IC_set_intervs_targ_pop_direct_entry(interv_records, targ_pop_direct_entry_DB):

    return interv_records


def IC_init_alt_PIN_age_group_set_1_records(interv_records, num_years_full):

    alt_PIN_age_group_set_1_records = []

    for interv_obj in interv_records:
        ID = icmvu.get_IC_interv_ID(interv_obj)
        targ_pop_mst_ID = icmvu.get_IC_interv_targ_pop_mst_ID(interv_obj)

        if targ_pop_mst_ID == ictpi.IC_TP_AGE_GROUP_SET_1_MST_ID:
            alt_PIN_age_group_set_1_rec = icmvd.IC_create_alt_PIN_age_group_set_1_rec(ID, num_years_full)
            alt_PIN_age_group_set_1_records.append(alt_PIN_age_group_set_1_rec)

    return alt_PIN_age_group_set_1_records


def IC_init_alt_PIN_age_group_set_2_records(interv_records, num_years_full):

    alt_PIN_age_group_set_2_records = []

    for interv_obj in interv_records:
        interv_ID = icmvu.get_IC_interv_ID(interv_obj)
        targ_pop_mst_ID = icmvu.get_IC_interv_targ_pop_mst_ID(interv_obj)

        if targ_pop_mst_ID == ictpi.IC_TP_AGE_GROUP_SET_2_MST_ID:
            alt_PIN_age_group_set_2_rec = icmvd.IC_create_alt_PIN_age_group_set_2_rec(interv_ID, num_years_full)
            alt_PIN_age_group_set_2_records.append(alt_PIN_age_group_set_2_rec)

    return alt_PIN_age_group_set_2_records


#######################################################################################################
#                                                                                                     #
#                                       Drugs and supplies                                            #
#                                                                                                     #
#######################################################################################################


def IC_init_drug_supply_records(drug_supply_DB, num_years, costing_mode, plan_type):
    drug_supply_records = []

    for drug_supply_DB_obj in drug_supply_DB:
        mstID = str(drug_supply_DB_obj[icdbc.IC_MST_ID_KEY_DSDB])
        name = drug_supply_DB_obj[icdbc.IC_ENGLISH_STRING_KEY_DSDB]
        string_constant = drug_supply_DB_obj[icdbc.IC_STR_CONST_KEY_DSDB]
        type_mstID = drug_supply_DB_obj[icdbc.IC_TYPE_MST_ID_KEY_DSCB]
        unit_cost = drug_supply_DB_obj[icdbc.IC_UNIT_COST_KEY_DSCB]
        applicable_prog_areas_list = drug_supply_DB_obj[icdbc.IC_PROG_AREA_FILTER_MST_IDS_KEY_DSCB]
        # str_constant = drug_supply_DB_obj[icdbk.IC_CONSTANT_KEY_DSDB]
        cost_type_LG_mstID = drug_supply_DB_obj[icdbc.IC_COST_TYPE_MST_ID_KEY_LG_DSCB]
        requires_cold_storage = drug_supply_DB_obj[icdbc.IC_COLD_STORAGE_KEY_LG_DSDB]

        drug_supply_dict = icmvd.IC_create_drug_supply_rec(
            mstID, name, True, cost_type_LG_mstID, type_mstID, requires_cold_storage, num_years, costing_mode, plan_type
        )
        icmvu.set_IC_drug_supply_string_constant(drug_supply_dict, string_constant)

        for t in acu.GBRange(1, num_years):
            icmvu.set_IC_drug_supply_unit_cost(drug_supply_dict, t - 1, unit_cost)

        # if len(applicable_prog_areas_list) > 0:
        #     for value in applicable_prog_areas_list:
        #         # If doing TB costing, then there is only one programme area, and it's TB. Ignore any programme area that is not TB and
        #         # change the ID to be the one for TB costing ("1") instead of the one for IHT ("22").
        #         if costing_mode == gbc.GB_TB_COSTING_MODE:
        #             if value == str(iccl.IC_IH_TB_MST_ID):
        #                 icmvu.add_IC_drug_supply_applic_prog_area(drug_supply_dict, str(iccl.IC_IH_TBC_TB_MST_ID))
        #         else:
        #             icmvu.add_IC_drug_supply_applic_prog_area(drug_supply_dict, value)

        # Applicable programme areas list is only for IHT. For other costing modes, show all drugs and supplies for all programme areas.
        if costing_mode == gbc.GB_IHT_COSTING_MODE:
            if len(applicable_prog_areas_list) > 0:
                for value in applicable_prog_areas_list:
                    icmvu.add_IC_drug_supply_applic_prog_area(drug_supply_dict, value)

        elif costing_mode == gbc.GB_TB_COSTING_MODE:
            for value in iccl.IC_IH_TI_PROG_AREA_MST_IDS:
                icmvu.add_IC_drug_supply_applic_prog_area(drug_supply_dict, str(value))

        elif costing_mode == gbc.GB_LIST_COSTING_MODE:
            for value in iccl.IC_CS_GROUP_MST_IDS:
                icmvu.add_IC_drug_supply_applic_prog_area(drug_supply_dict, str(value))

        drug_supply_records.append(drug_supply_dict)

    return drug_supply_records


#######################################################################################################
#                                                                                                     #
#                                       Treatment input groups   (TIGs)                               #
#                                                                                                     #
#######################################################################################################


def IC_init_treatment_input_group_records(interv_records, treatment_input_group_DB):

    TIG_drug_supply_records, TIG_med_personnel_records, TIG_outpat_inpat_records = [], [], []

    for TIG_DB_obj in treatment_input_group_DB:
        interv_ID = TIG_DB_obj[icdbc.IC_INTERV_MST_ID_KEY_TIGDB]

        # The database has interventions in it for all modes (IHT, TB Costing, LiST Costing). Only create records for interventions in the
        # mode the projection is using. The intervention records should only have interventions in that mode.
        interv_rec = icmvu.get_IC_interv_rec(interv_records, interv_ID)

        if type(interv_rec) is dict:
            deliv_chan_ID = TIG_DB_obj[icdbc.IC_DELIV_CHAN_MST_ID_KEY_TIGDB]
            treat_input_type_mst_ID = TIG_DB_obj[icdbc.IC_TREAT_INPUT_TYPE_MST_ID_KEY_TIGDB]
            treat_input_group_ID = TIG_DB_obj[icdbc.IC_GROUP_MST_ID_KEY_TIGDB]
            treat_input_group_name = TIG_DB_obj[icdbc.IC_GROUP_NAME_KEY_TIGDB]
            treat_input_string_constant = TIG_DB_obj[icdbc.IC_GROUP_STR_CONST_KEY_TIGDB]

            TIG_rec = icmvd.IC_create_treat_input_group_rec(
                interv_ID, deliv_chan_ID, treat_input_group_ID, treat_input_group_name
            )
            icmvu.set_IC_TIG_string_constant(TIG_rec, treat_input_string_constant)

            if treat_input_type_mst_ID == icc.IC_TI_DRUGS_SUPPLIES_MST_ID:
                icmvu.add_IC_TIG_rec(TIG_drug_supply_records, TIG_rec)

            elif treat_input_type_mst_ID == icc.IC_TI_MED_PERSONNEL_TIME_MST_ID:
                icmvu.add_IC_TIG_rec(TIG_med_personnel_records, TIG_rec)

            elif treat_input_type_mst_ID == icc.IC_TI_OUTPAT_VISITS_INPAT_DAYS_MST_ID:
                icmvu.add_IC_TIG_rec(TIG_outpat_inpat_records, TIG_rec)

    return TIG_drug_supply_records, TIG_med_personnel_records, TIG_outpat_inpat_records


#######################################################################################################
#                                                                                                     #
#                                       Treatment inputs (TIs)                                        #
#                                                                                                     #
#######################################################################################################


def IC_init_treatment_input_records(interv_records, treatment_input_DB, num_years):

    TI_drug_supply_records, TI_med_personnel_records, TI_outpat_inpat_records = [], [], []

    for TI_DB_obj in treatment_input_DB:
        interv_ID = str(TI_DB_obj[icdbc.IC_INTERV_MST_ID_KEY_TIDB])

        # The database has interventions in it for all modes (IHT, TB Costing, LiST Costing). Only create records for interventions in the
        # mode the projection is using. The intervention records should only have interventions in that mode.
        interv_rec = icmvu.get_IC_interv_rec(interv_records, interv_ID)

        if type(interv_rec) is dict:
            deliv_chan_ID = TI_DB_obj[icdbc.IC_DELIV_CHAN_MST_ID_KEY_TIDB]
            treat_input_type_mst_ID = TI_DB_obj[icdbc.IC_TREAT_INPUT_TYPE_MST_ID_KEY_TIDB]
            treat_input_group_ID = TI_DB_obj[icdbc.IC_GROUP_MST_ID_KEY_TIDB]
            treatment_input_mst_ID = TI_DB_obj[icdbc.IC_TREATMENT_INPUT_MST_ID_KEY_TIDB]

            perc_applied = TI_DB_obj[icdbc.IC_PERC_APPLIED_KEY_TIDB]
            note = TI_DB_obj[icdbc.IC_NOTE_KEY_TIDB]
            note_string_constant = TI_DB_obj[icdbc.IC_NOTE_STR_CONST_KEY_TIDB]
            num_items = TI_DB_obj[icdbc.IC_NUM_ITEMS_KEY_TIDB]
            times_per_day_or_min = TI_DB_obj[icdbc.IC_TIMES_PER_DAY_MIN_KEY_TIDB]
            days_per_case_or_num_days = TI_DB_obj[icdbc.IC_DAYS_PER_CASE_NUM_DAYS_KEY_TIDB]
            units_per_case_or_person = TI_DB_obj[icdbc.IC_UNITS_PER_CASE_PERSON_KEY_TIDB]

            TI_rec = icmvd.IC_create_treat_input_rec(
                interv_ID,
                deliv_chan_ID,
                treat_input_type_mst_ID,
                treat_input_group_ID,
                treatment_input_mst_ID,
                num_years,
            )
            icmvu.set_IC_TI_note_string_constant(TI_rec, note_string_constant)

            # Set dict values according to the item type.

            if treat_input_type_mst_ID == icc.IC_TI_DRUGS_SUPPLIES_MST_ID:
                icmvu.set_IC_TI_drug_supply_times_per_day(TI_rec, times_per_day_or_min)
                icmvu.set_IC_TI_drug_supply_days_per_case(TI_rec, days_per_case_or_num_days)
                icmvu.set_IC_TI_drug_supply_number(TI_rec, num_items)

            elif treat_input_type_mst_ID == icc.IC_TI_MED_PERSONNEL_TIME_MST_ID:
                icmvu.set_IC_TI_med_personnel_num_days(TI_rec, days_per_case_or_num_days)
                icmvu.set_IC_TI_med_personnel_minutes(TI_rec, times_per_day_or_min)

            elif treat_input_type_mst_ID == icc.IC_TI_OUTPAT_VISITS_INPAT_DAYS_MST_ID:
                icmvu.set_IC_TI_outpat_inpat_units_per_case(TI_rec, units_per_case_or_person)

            # All treatment input dict types

            for t in acu.GBRange(1, num_years):
                icmvu.set_IC_TI_perc_applied(TI_rec, t - 1, perc_applied)
            icmvu.set_IC_TI_note(TI_rec, note)

            if treat_input_type_mst_ID == icc.IC_TI_DRUGS_SUPPLIES_MST_ID:
                icmvu.add_IC_TI_rec(TI_drug_supply_records, TI_rec)

            elif treat_input_type_mst_ID == icc.IC_TI_MED_PERSONNEL_TIME_MST_ID:
                icmvu.add_IC_TI_rec(TI_med_personnel_records, TI_rec)

            elif treat_input_type_mst_ID == icc.IC_TI_OUTPAT_VISITS_INPAT_DAYS_MST_ID:
                icmvu.add_IC_TI_rec(TI_outpat_inpat_records, TI_rec)

    return TI_drug_supply_records, TI_med_personnel_records, TI_outpat_inpat_records


#######################################################################################################
#                                                                                                     #
#                                       Target populations                                            #
#                                                                                                     #
#######################################################################################################


def IC_init_targ_pop_def_records(targ_pop_DB, costing_mode):
    targ_pop_def_records = []

    for targ_pop_DB_obj in targ_pop_DB:
        # constant = targ_pop_DB_obj[icdbk.IC_CONSTANT_KEY_TPDB]
        mst_ID = targ_pop_DB_obj[icdbc.IC_MST_ID_KEY_TPDB]
        name = targ_pop_DB_obj[icdbc.IC_NAME_KEY_TPDB]
        string_constant = targ_pop_DB_obj[icdbc.IC_STR_CONST_KEY_TPDB]
        required_modules_list = targ_pop_DB_obj[icdbc.IC_REQ_MOD_MST_IDS_KEY_TPDB]
        applicable_prog_areas_list = []
        targ_pop_def_rec = icmvd.IC_create_targ_pop_def_rec(name, string_constant, mst_ID)

        if costing_mode == gbc.GB_IHT_COSTING_MODE:
            applicable_prog_areas_list = targ_pop_DB_obj[icdbc.IC_APPLIC_PROG_AREA_IDS_IHT_KEY_TPDB]

        elif costing_mode == gbc.GB_TB_COSTING_MODE:
            applicable_prog_areas_list = targ_pop_DB_obj[icdbc.IC_APPLIC_PROG_AREA_IDS_TB_KEY_TPDB]

        elif costing_mode == gbc.GB_LIST_COSTING_MODE:
            applicable_prog_areas_list = targ_pop_DB_obj[icdbc.IC_APPLIC_PROG_AREA_IDS_LIST_KEY_TPDB]

        if len(applicable_prog_areas_list) > 0:
            for value in applicable_prog_areas_list:
                icmvu.add_IC_def_targ_pop_applic_prog_area(targ_pop_def_rec, str(value))

        # if len(applicable_prog_areas_list) > 0:
        #     for value in applicable_prog_areas_list:
        #         # If doing TB costing, then there is only one programme area, and it's TB. Ignore any programme area that is not TB and
        #         # change the ID to be the one for TB costing ("1") instead of the one for IHT ("22").
        #         if costing_mode == gbc.GB_TB_COSTING_MODE:
        #             if value == str(iccl.IC_IH_TB_MST_ID):
        #                 icmvu.add_IC_def_targ_pop_applic_prog_area(targ_pop_def_rec, iccl.IH_TI_IVG_TB_MST_ID)
        #         else:
        #             icmvu.add_IC_def_targ_pop_applic_prog_area(targ_pop_def_rec, str(value))

        if len(required_modules_list) > 0:
            for value in required_modules_list:
                icmvu.add_IC_def_targ_pop_req_mod(targ_pop_def_rec, value)

        targ_pop_def_records.append(targ_pop_def_rec)

    return targ_pop_def_records


def IC_set_drug_cost_per_avg_case(interv_records, num_years, drug_cost_per_avg_case_DB):
    drug_cost_per_avg_case = []

    interv_list = [interv_rec[icmvf.IC_INTERV_ID] for interv_rec in interv_records]

    for rec in drug_cost_per_avg_case_DB:
        if rec[icmvf.IC_F_INTERV_ID] in interv_list:
            rec_adjusted_years = deepcopy(rec)
            rec_adjusted_years[icmvf.IC_F_VALUE] = np.full((num_years), rec[icmvf.IC_F_VALUE][0]).tolist()
            drug_cost_per_avg_case.append(rec_adjusted_years)

    return drug_cost_per_avg_case


def IC_set_supply_cost_per_avg_case(interv_records, num_years, supply_cost_per_avg_case_DB):
    supply_cost_per_avg_case = []

    interv_list = [interv_rec[icmvf.IC_INTERV_ID] for interv_rec in interv_records]

    for rec in supply_cost_per_avg_case_DB:
        if rec[icmvf.IC_F_INTERV_ID] in interv_list:
            rec_adjusted_years = deepcopy(rec)
            rec_adjusted_years[icmvf.IC_F_VALUE] = np.full((num_years), rec[icmvf.IC_F_VALUE][0]).tolist()
            supply_cost_per_avg_case.append(rec_adjusted_years)

    return supply_cost_per_avg_case


def IC_set_med_personnel_min_per_avg_case_def(interv_records, num_years, med_personnel_min_per_avg_case_DB):
    med_personnel_min_per_avg_case_def = []

    interv_list = [interv_rec[icmvf.IC_INTERV_ID] for interv_rec in interv_records]

    for rec in med_personnel_min_per_avg_case_DB:
        if rec[icmvf.IC_F_INTERV_ID] in interv_list:
            rec_adjusted_years = deepcopy(rec)
            rec_adjusted_years[icmvf.IC_F_VALUE] = np.full((num_years), rec[icmvf.IC_F_VALUE][0]).tolist()
            med_personnel_min_per_avg_case_def.append(rec_adjusted_years)

    return med_personnel_min_per_avg_case_def


#######################################################################################################
#                                                                                                     #
#                                       Target populations                                            #
#                                                                                                     #
#######################################################################################################


def IC_set_health_system_costs_MVs(health_system_costs_DB_CS, num_years_inputs):
    supply_chain_cost_perc_commodity_cost = icmvd.IC_init_year_arr(num_years_inputs, 0).tolist()
    infrastructure_investment = icmvd.IC_init_year_arr(num_years_inputs, 0.0).tolist()

    for t in acu.GBRange(1, num_years_inputs):
        supply_chain_cost_perc_commodity_cost[t - 1] = round(
            health_system_costs_DB_CS[icdbc.IC_SUPPLY_CHAIN_COST_PERC_COMMODITY_COST_KEY_HSCDB]
        )
        infrastructure_investment[t - 1] = health_system_costs_DB_CS[icdbc.IC_INFRASTRUCTURE_INVESTMENT_RATIO_KEY_HSCDB]

    ratio_other_health_system_to_interv_costs = health_system_costs_DB_CS[
        icdbc.IC_OTHER_TO_INVESTMENT_COSTS_RATIO_KEY_HSCDB
    ]
    income_level = health_system_costs_DB_CS[icdbc.IC_INCOME_LEVEL_KEY_HSCDB]
    supply_chain_status = health_system_costs_DB_CS[icdbc.IC_SUPPLY_CHAIN_STATUS_KEY_HSCDB]

    return (
        supply_chain_cost_perc_commodity_cost,
        infrastructure_investment,
        ratio_other_health_system_to_interv_costs,
        income_level,
        supply_chain_status,
    )


def IC_set_outpat_visit_inpat_day_costs_TB_MVs(outpat_visit_inpat_day_costs_TB_DB):
    outpat_visit_inpat_day_costs = deepcopy(
        outpat_visit_inpat_day_costs_TB_DB[icdbc.IC_COST_PER_OUTPAT_VISIT_INPAT_DAY_KEY_OVIDCTBDB]
    )

    return outpat_visit_inpat_day_costs


def IC_set_outpat_visit_inpat_day_costs_CS_MVs(outpat_visit_inpat_day_costs_CS_DB):
    other_recurrent_costs = deepcopy(outpat_visit_inpat_day_costs_CS_DB[icdbc.IC_OTHER_RECURRENT_COSTS_KEY_OVIDCCSDB])
    capital_costs = deepcopy(outpat_visit_inpat_day_costs_CS_DB[icdbc.IC_CAPITAL_COSTS_KEY_OVIDCCSDB])

    return other_recurrent_costs, capital_costs
