import numpy as np

import SpectrumCommon.Const.GB.GBConst as gbc

import SpectrumCommon.Const.LG.LGConst as lgc
import SpectrumCommon.Const.LG.LGModVarFields as lgmvf
import SpectrumCommon.Modvars.LG.LGModVarUtil as lgmvu
import SpectrumCommon.Const.LG.LGDatabaseKeys as lgdbk
import SpectrumCommon.Const.LG.LGTags as lgmvt
import SpectrumCommon.Const.PJ.PJNTags as pjmvt


#######################################################################################################
#                                                                                                     #
#                                   Supply chain level records                                        #
#                                                                                                     #
#######################################################################################################


def LG_create_supply_chain_level_record(ID: int, name: str, string_const: str, num_years: int):
    return {
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_ID: ID,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_NAME: name,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_STR_CONST: string_const,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_CUSTOM: False,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_AMOUNT: 0,
        # Baseline
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_TOTAL_OPERATING_COSTS: 0,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_ANNUAL_WATER_COST: 0,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_ANNUAL_ELECTRICAL_COST: 0,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_OTHER_OPERATING_COSTS: 0,
        # Target setting
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_TOTAL_CONSTRUCT_COSTS: 0,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_LAND_COST: 0,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_COST_CONSTRUCT_SQ_M: 0,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_SIZE_SQ_M: 0,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_NUM_BUILT_BY_YEAR: [0] * num_years,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_NUM_REHAB_BY_YEAR: [0] * num_years,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_REHAB_COST: 0,
        # Volume analytics
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_NUM_RESUPPLY_VISITS_BY_YEAR: [0] * num_years,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_CAPACITY: 0,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_NUM_MONTHS_SAFETY_STOCK: 0,
        lgmvf.LG_SUPPLY_CHAIN_LEVEL_DISTANCE_TO_SUPPLYING_WAREHOUSE: 0,
    }


def LG_init_supply_chain_level_records(num_years: int):
    supply_chain_level_records = []

    for default_supply_chain_level in lgc.LG_DEFAULT_SUPPLY_CHAIN_LEVELS:
        default_level_rec = LG_create_supply_chain_level_record(
            default_supply_chain_level[lgmvf.LG_SUPPLY_CHAIN_LEVEL_ID],
            default_supply_chain_level[lgmvf.LG_SUPPLY_CHAIN_LEVEL_NAME],
            default_supply_chain_level[lgmvf.LG_SUPPLY_CHAIN_LEVEL_STR_CONST],
            num_years,
        )
        supply_chain_level_records.append(default_level_rec)

    return supply_chain_level_records


#######################################################################################################
#                                                                                                     #
#                                   Warehouse records                                                 #
#                                                                                                     #
#######################################################################################################


def LG_create_warehouse_record(
    ID: str,
    name: str,
    parent_ID: str,
    supply_chain_level_ID: int,
    num_supply_chain_levels: int,
    warehouse_type: int,
    num_years: int,
    custom: bool = True,
):
    return {
        lgmvf.LG_WAREHOUSE_ID: ID,
        lgmvf.LG_WAREHOUSE_NAME: name,
        lgmvf.LG_WAREHOUSE_PARENT_ID: parent_ID,
        lgmvf.LG_WAREHOUSE_SUPPLY_CHAIN_LEVEL_ID: supply_chain_level_ID,
        lgmvf.LG_WAREHOUSE_TYPE: warehouse_type,
        lgmvf.LG_WAREHOUSE_CUSTOM: custom,
        # Baseline
        lgmvf.LG_WAREHOUSE_TOTAL_OPERATING_COSTS: 0,
        lgmvf.LG_WAREHOUSE_ANNUAL_ELECTRICAL_COST: 0,
        lgmvf.LG_WAREHOUSE_ANNUAL_WATER_COST: 0,
        lgmvf.LG_WAREHOUSE_OTHER_OPERATING_COSTS: 0,
        lgmvf.LG_WAREHOUSE_TOTAL_CONSTRUCT_COSTS: 0,
        lgmvf.LG_WAREHOUSE_LAND_COST: 0,
        lgmvf.LG_WAREHOUSE_COST_CONSTRUCT_SQ_M: 0,
        lgmvf.LG_WAREHOUSE_SIZE_SQ_M: 0,
        lgmvf.LG_WAREHOUSE_LEVEL_AMOUNTS: LG_init_dict_by_level(supply_chain_level_ID, num_supply_chain_levels),
        lgmvf.LG_WAREHOUSE_AVG_OPERATING_COSTS_BY_LEVEL: {
            lgmvf.LG_WAREHOUSE_ANNUAL_ELECTRICAL_COST: LG_init_dict_by_level(
                supply_chain_level_ID, num_supply_chain_levels
            ),
            lgmvf.LG_WAREHOUSE_OTHER_OPERATING_COSTS: LG_init_dict_by_level(
                supply_chain_level_ID, num_supply_chain_levels
            ),
            lgmvf.LG_WAREHOUSE_TOTAL_OPERATING_COSTS: LG_init_dict_by_level(
                supply_chain_level_ID, num_supply_chain_levels
            ),
            lgmvf.LG_WAREHOUSE_ANNUAL_WATER_COST: LG_init_dict_by_level(supply_chain_level_ID, num_supply_chain_levels),
        },
        # Target setting
        lgmvf.LG_WAREHOUSE_AVG_CONSTRUCTION_COSTS_BY_LEVEL: {
            lgmvf.LG_WAREHOUSE_LAND_COST: LG_init_dict_by_level(supply_chain_level_ID, num_supply_chain_levels),
            lgmvf.LG_WAREHOUSE_TOTAL_CONSTRUCT_COSTS: LG_init_dict_by_level(
                supply_chain_level_ID, num_supply_chain_levels
            ),
            lgmvf.LG_WAREHOUSE_COST_CONSTRUCT_SQ_M: LG_init_dict_by_level(
                supply_chain_level_ID, num_supply_chain_levels
            ),
            lgmvf.LG_WAREHOUSE_SIZE_SQ_M: LG_init_dict_by_level(supply_chain_level_ID, num_supply_chain_levels),
        },
        lgmvf.LG_WAREHOUSE_NUM_BUILT_BY_YEAR: [0] * num_years,
        lgmvf.LG_WAREHOUSE_NUM_BUILT_BY_YEAR_BY_LEVEL: LG_init_dict_by_level(
            supply_chain_level_ID,
            num_supply_chain_levels,
            [0] * num_years,
        ),
        lgmvf.LG_WAREHOUSE_NUM_REHAB_BY_YEAR: [0] * num_years,
        lgmvf.LG_WAREHOUSE_NUM_REHAB_BY_YEAR_BY_LEVEL: LG_init_dict_by_level(
            supply_chain_level_ID,
            num_supply_chain_levels,
            [0] * num_years,
        ),
        lgmvf.LG_WAREHOUSE_REHAB_COST: 0,
        lgmvf.LG_WAREHOUSE_REHAB_COSTS_BY_LEVEL: LG_init_dict_by_level(supply_chain_level_ID, num_supply_chain_levels),
        lgmvf.LG_WAREHOUSE_NUM_MOVED: 0,
        lgmvf.LG_WAREHOUSE_NUM_MOVED_BY_LEVEL: LG_init_dict_by_level(supply_chain_level_ID, num_supply_chain_levels, 0),
        lgmvf.LG_WAREHOUSE_TARGET_TRANSFER_SOURCE: None,
        lgmvf.LG_WAREHOUSE_TARGET_TRANSFER_SOURCE_BY_LEVEL: LG_init_dict_by_level(
            supply_chain_level_ID, num_supply_chain_levels, None
        ),
        lgmvf.LG_WAREHOUSE_YEAR_MOVED: None,
        lgmvf.LG_WAREHOUSE_YEAR_MOVED_BY_LEVEL: LG_init_dict_by_level(
            supply_chain_level_ID, num_supply_chain_levels, None
        ),
        # Volume analytics
        lgmvf.LG_WAREHOUSE_NUM_RESUPPLY_VISITS_BY_YEAR: [0] * num_years,
        lgmvf.LG_WAREHOUSE_NUM_RESUPPLY_VISITS_BY_YEAR_BY_LEVEL: LG_init_dict_by_level(
            supply_chain_level_ID,
            num_supply_chain_levels,
            [0] * num_years,
        ),
        lgmvf.LG_WAREHOUSE_AVG_PERC_POP_SERVED: [0] * num_years,
        lgmvf.LG_WAREHOUSE_CAPACITY: 0,
        lgmvf.LG_WAREHOUSE_CAPACITY_BY_LEVEL: LG_init_dict_by_level(
            supply_chain_level_ID,
            num_supply_chain_levels,
            0,
        ),
        lgmvf.LG_WAREHOUSE_NUM_MONTHS_SAFETY_STOCK: 0,
        lgmvf.LG_WAREHOUSE_NUM_MONTHS_SAFETY_STOCK_BY_LEVEL: LG_init_dict_by_level(
            supply_chain_level_ID,
            num_supply_chain_levels,
            0,
        ),
        lgmvf.LG_WAREHOUSE_DISTANCE_TO_SUPPLYING_WAREHOUSE: 0,
        lgmvf.LG_WAREHOUSE_DISTANCE_TO_SUPPLYING_WAREHOUSE_BY_LEVEL: LG_init_dict_by_level(
            supply_chain_level_ID,
            num_supply_chain_levels,
            0,
        ),
    }


def LG_init_dict_by_level(
    supply_chain_level_ID: int, num_supply_chain_levels: int, default_value: np.ndarray | dict | list | int | None = 0
):
    result = {}
    for i in range(supply_chain_level_ID + 1, num_supply_chain_levels + 1):
        if isinstance(default_value, (np.ndarray, list)):
            result[i] = default_value.copy()
        else:
            result[i] = default_value
    return result


def LG_init_dict_by_warehouse_by_level(
    warehouse_records: list, num_supply_chain_levels: int, default_value: np.ndarray | list | int = 0
):
    result = {}
    for warehouse_record in warehouse_records:
        warehouse_ID = warehouse_record.get(lgmvf.LG_WAREHOUSE_ID, None)
        warehouse_supply_chain_level_ID = warehouse_record.get(lgmvf.LG_WAREHOUSE_SUPPLY_CHAIN_LEVEL_ID, None)
        result[warehouse_ID] = LG_init_dict_by_level(
            warehouse_supply_chain_level_ID, num_supply_chain_levels, default_value
        )
    return result


def LG_init_dict_by_warehouse(warehouse_records: list, default_value: np.ndarray | list | int = 0):
    result = {}
    for warehouse_record in warehouse_records:
        warehouse_ID = warehouse_record.get(lgmvf.LG_WAREHOUSE_ID, None)
        if isinstance(default_value, (np.ndarray, list)):
            result[warehouse_ID] = default_value.copy()
        else:
            result[warehouse_ID] = default_value
    return result


def LG_init_dict_by_vehicle(vehicle_records: list, default_value: int = 0):
    result = {}
    for vehicle_record in vehicle_records:
        vehicle_ID = vehicle_record.get(lgmvf.LG_VEHICLE_TYPE_ID)
        result[vehicle_ID] = default_value
    return result


#######################################################################################################
#                                                                                                     #
#                                   Vehicle type records                                              #
#                                                                                                     #
#######################################################################################################


def LG_create_vehicle_type_record(
    ID: str,
    name: str,
    string_const: str,
    num_supply_chain_levels: int,
    num_years: int,
    warehouse_records: list = [],
):
    return {
        lgmvf.LG_VEHICLE_TYPE_ID: ID,
        lgmvf.LG_VEHICLE_TYPE_NAME: name,
        lgmvf.LG_VEHICLE_TYPE_STR_CONST: string_const,
        lgmvf.LG_VEHICLE_TYPE_CUSTOM: False,
        # Baseline
        lgmvf.LG_VEHICLE_TYPE_AVG_AMOUNT_BY_LEVEL_AGGR: LG_init_dict_by_level(0, num_supply_chain_levels),
        lgmvf.LG_VEHICLE_TYPE_AVG_AMOUNT_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels
        ),
        lgmvf.LG_VEHICLE_TYPE_AMOUNT_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(warehouse_records),
        lgmvf.LG_VEHICLE_TYPE_UNIT_COST: 0,
        lgmvf.LG_VEHICLE_TYPE_WORKING_LIFE_YEARS: [0] * num_years,
        lgmvf.LG_VEHICLE_TYPE_FUEL_CONSUMPTION: 0,
        lgmvf.LG_VEHICLE_TYPE_REP_MAINT_COST_PERC_CAP_COST: 0,
        lgmvf.LG_VEHICLE_TYPE_NUM_TRIPS: [0] * num_years,
        lgmvf.LG_VEHICLE_TYPE_AVG_KM_PER_TRIP: [0] * num_years,
        lgmvf.LG_VEHICLE_TYPE_COST_PETROL_PER_VEHIC_YEAR: 0,
        # Target setting
        lgmvf.LG_VEHICLE_TYPE_TARG_WAREHOUSE_STD_BY_LEVEL_AGGR: LG_init_dict_by_level(0, num_supply_chain_levels),
        lgmvf.LG_VEHICLE_TYPE_TARG_WAREHOUSE_STD_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels
        ),
        lgmvf.LG_VEHICLE_TYPE_TARG_WAREHOUSE_STD_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(warehouse_records),
        lgmvf.LG_VEHICLE_TYPE_TARG_NUM_AVAILABLE_BY_LEVEL_AGGR: LG_init_dict_by_level(
            0, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_VEHICLE_TYPE_TARG_NUM_AVAILABLE_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_VEHICLE_TYPE_TARG_NUM_AVAILABLE_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(
            warehouse_records, [0] * num_years
        ),
        lgmvf.LG_VEHICLE_TYPE_TARG_EXISTING_PLANS_BY_LEVEL_AGGR: LG_init_dict_by_level(
            0, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_VEHICLE_TYPE_TARG_EXISTING_PLANS_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_VEHICLE_TYPE_TARG_EXISTING_PLANS_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(
            warehouse_records, [0] * num_years
        ),
        # Volume analytics
        lgmvf.LG_VEHICLE_TYPE_PERC_SERVICED_BY_LEVEL_AGGR: LG_init_dict_by_level(
            0, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_VEHICLE_TYPE_PERC_SERVICED_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(
            warehouse_records, [0] * num_years
        ),
        lgmvf.LG_VEHICLE_TYPE_PERC_SERVICED_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_VEHICLE_TYPE_DWELL_TIME_BY_LEVEL_AGGR: LG_init_dict_by_level(0, num_supply_chain_levels),
        lgmvf.LG_VEHICLE_TYPE_DWELL_TIME_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(warehouse_records),
        lgmvf.LG_VEHICLE_TYPE_DWELL_TIME_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels
        ),
        lgmvf.LG_VEHICLE_TYPE_CAPACITY: 0,
        lgmvf.LG_VEHICLE_TYPE_AVG_SPEED: 0,
        lgmvf.LG_VEHICLE_TYPE_MAX_DAYS_ON_ROUTE: 0,
    }


def LG_init_vehicle_type_records(num_supply_chain_levels: int, num_years: int):
    vehicle_type_records = []

    for default_vehicle_type in lgc.LG_DEFAULT_VEHICLE_TYPES:
        default_vehicle_rec = LG_create_vehicle_type_record(
            str(default_vehicle_type[lgmvf.LG_VEHICLE_TYPE_ID]),
            default_vehicle_type[lgmvf.LG_VEHICLE_TYPE_NAME],
            default_vehicle_type[lgmvf.LG_VEHICLE_TYPE_STR_CONST],
            num_supply_chain_levels,
            num_years,
            [],
        )
        vehicle_type_records.append(default_vehicle_rec)

    return vehicle_type_records


#######################################################################################################
#                                                                                                     #
#                                   Worker type records                                               #
#                                                                                                     #
#######################################################################################################


def LG_create_worker_type_record(
    ID: str,
    name: str,
    string_const: str,
    num_supply_chain_levels: int,
    num_years: int,
    vehicle_records: list = [],
    warehouse_records: list = [],
):
    return {
        lgmvf.LG_WORKER_TYPE_ID: ID,
        lgmvf.LG_WORKER_TYPE_NAME: name,
        lgmvf.LG_WORKER_TYPE_STR_CONST: string_const,
        lgmvf.LG_WORKER_TYPE_CUSTOM: False,
        # Baseline
        lgmvf.LG_WORKER_TYPE_ANNUAL_WAGES: 0.0,
        lgmvf.LG_WORKER_TYPE_ANNUAL_REAL_SALARY_INC: 0,
        lgmvf.LG_WORKER_TYPE_ANNUAL_BENEFITS: 0.0,
        lgmvf.LG_WORKER_TYPE_ANNUAL_BENEFITS_ADJUST: 0,
        lgmvf.LG_WORKER_TYPE_AVG_AMOUNT_BY_LEVEL_AGGR: LG_init_dict_by_level(0, num_supply_chain_levels),
        lgmvf.LG_WORKER_TYPE_AVG_AMOUNT_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels
        ),
        lgmvf.LG_WORKER_TYPE_AMOUNT_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(warehouse_records),
        # Target setting
        lgmvf.LG_WORKER_TYPE_TARG_CONFIG_OPTION: lgc.LG_TARGET_CONFIG_EXISTING_PLANS_MST_ID,
        lgmvf.LG_WORKER_TYPE_TARG_WAREHOUSE_STD_BY_LEVEL_AGGR: LG_init_dict_by_level(0, num_supply_chain_levels),
        lgmvf.LG_WORKER_TYPE_TARG_WAREHOUSE_STD_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels
        ),
        lgmvf.LG_WORKER_TYPE_TARG_WAREHOUSE_STD_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(warehouse_records),
        lgmvf.LG_WORKER_TYPE_NUM_EXISTING_PLANS_BY_LEVEL_AGGR: LG_init_dict_by_level(
            0, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_WORKER_TYPE_NUM_EXISTING_PLANS_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_WORKER_TYPE_NUM_EXISTING_PLANS_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(
            warehouse_records, [0] * num_years
        ),
        lgmvf.LG_WORKER_TYPE_TARG_NUM_AVAILABLE_BY_LEVEL_AGGR: LG_init_dict_by_level(
            0, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_WORKER_TYPE_TARG_NUM_AVAILABLE_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_WORKER_TYPE_TARG_NUM_AVAILABLE_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(
            warehouse_records, [0] * num_years
        ),
        lgmvf.LG_WORKER_TYPE_VEHICLE_STD: LG_init_dict_by_vehicle(vehicle_records, 1),
        # Volume analytics
        lgmvf.LG_WORKER_TYPE_CLASSIFICATION: lgc.LG_WORKER_CLASSIFICATION_OTHER,
        lgmvf.LG_WORKER_TYPE_CAPACITY: 0,
    }


def LG_init_worker_type_records(
    num_supply_chain_levels: int,
    vehicle_type_records: list,
    num_years: int,
):
    worker_type_records = []

    for default_worker_type in lgc.LG_DEFAULT_WORKER_TYPES:
        default_worker_rec = LG_create_worker_type_record(
            str(default_worker_type[lgmvf.LG_WORKER_TYPE_ID]),
            default_worker_type[lgmvf.LG_WORKER_TYPE_NAME],
            default_worker_type[lgmvf.LG_WORKER_TYPE_STR_CONST],
            num_supply_chain_levels,
            num_years,
            vehicle_type_records,
            [],
        )
        worker_type_records.append(default_worker_rec)

    return worker_type_records


#######################################################################################################
#                                                                                                     #
#                                   Cold chain records                                                #
#                                                                                                     #
#######################################################################################################


def LG_create_cold_chain_record(
    ID: str,
    name: str,
    string_const: str,
    cold_chain_type: int,
    num_supply_chain_levels: int,
    num_years: int,
    warehouse_records: list = [],
):
    return {
        lgmvf.LG_COLD_CHAIN_ID: ID,
        lgmvf.LG_COLD_CHAIN_NAME: name,
        lgmvf.LG_COLD_CHAIN_STR_CONST: string_const,
        lgmvf.LG_COLD_CHAIN_CUSTOM: False,
        lgmvf.LG_COLD_CHAIN_TYPE: cold_chain_type,
        # Baseline
        lgmvf.LG_COLD_CHAIN_AVG_AMOUNT_BY_LEVEL_AGGR: LG_init_dict_by_level(0, num_supply_chain_levels),
        lgmvf.LG_COLD_CHAIN_AVG_AMOUNT_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels
        ),
        lgmvf.LG_COLD_CHAIN_AMOUNT_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(warehouse_records),
        lgmvf.LG_COLD_CHAIN_UNIT_COST: 0,
        lgmvf.LG_COLD_CHAIN_CAPACITY: 0,
        lgmvf.LG_COLD_CHAIN_MAINT_COST_PERC_CAP_COST: 0,
        lgmvf.LG_COLD_CHAIN_WORKING_LIFE_YEARS: [0] * num_years,
        # Target setting
        lgmvf.LG_COLD_CHAIN_TARG_WAREHOUSE_STD_BY_LEVEL_AGGR: LG_init_dict_by_level(0, num_supply_chain_levels),
        lgmvf.LG_COLD_CHAIN_TARG_WAREHOUSE_STD_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels
        ),
        lgmvf.LG_COLD_CHAIN_TARG_WAREHOUSE_STD_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(warehouse_records),
        lgmvf.LG_COLD_CHAIN_TARG_NUM_AVAILABLE_BY_LEVEL_AGGR: LG_init_dict_by_level(
            0, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_COLD_CHAIN_TARG_NUM_AVAILABLE_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_COLD_CHAIN_TARG_NUM_AVAILABLE_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(
            warehouse_records, [0] * num_years
        ),
        lgmvf.LG_COLD_CHAIN_TARG_EXISTING_PLANS_BY_LEVEL_AGGR: LG_init_dict_by_level(
            0, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_COLD_CHAIN_TARG_EXISTING_PLANS_BY_LEVEL_DISAG: LG_init_dict_by_warehouse_by_level(
            warehouse_records, num_supply_chain_levels, [0] * num_years
        ),
        lgmvf.LG_COLD_CHAIN_TARG_EXISTING_PLANS_BY_WAREHOUSE_DISAG: LG_init_dict_by_warehouse(
            warehouse_records, [0] * num_years
        ),
    }


def LG_init_cold_chain_records(num_supply_chain_levels: int, num_years: int):
    cold_chain_records = []

    for default_cold_chain_item in lgc.LG_DEFAULT_COLD_CHAIN_RECORDS:
        default_cold_chain_rec = LG_create_cold_chain_record(
            str(default_cold_chain_item[lgmvf.LG_COLD_CHAIN_ID]),
            default_cold_chain_item[lgmvf.LG_COLD_CHAIN_NAME],
            default_cold_chain_item[lgmvf.LG_COLD_CHAIN_STR_CONST],
            default_cold_chain_item[lgmvf.LG_COLD_CHAIN_TYPE],
            num_supply_chain_levels,
            num_years,
            [],
        )
        lgmvu.set_LG_cold_chain_rec_capacity(
            default_cold_chain_rec, default_cold_chain_item[lgmvf.LG_COLD_CHAIN_CAPACITY]
        )
        lgmvu.set_LG_cold_chain_rec_unit_cost(
            default_cold_chain_rec, default_cold_chain_item[lgmvf.LG_COLD_CHAIN_UNIT_COST]
        )
        cold_chain_records.append(default_cold_chain_rec)

    return cold_chain_records


def LG_init_default_cold_chain_records(default_cold_chain_records_DB):
    default_cold_chain_records = []

    for cold_chain_DB_obj in default_cold_chain_records_DB:
        default_cold_chain_records.append(
            {
                lgmvf.LG_COLD_CHAIN_ID: str(cold_chain_DB_obj[lgdbk.LG_COLD_CHAIN_ID_KEY]),
                lgmvf.LG_COLD_CHAIN_TYPE: cold_chain_DB_obj[lgdbk.LG_COLD_CHAIN_TYPE_KEY],
                lgmvf.LG_COLD_CHAIN_NAME: cold_chain_DB_obj[lgdbk.LG_COLD_CHAIN_NAME_KEY],
            }
        )

    return default_cold_chain_records


#######################################################################################################
#                                                                                                     #
#                                   Third party logistics type records                                #
#                                                                                                     #
#######################################################################################################


def LG_create_third_party_logistics_type_record(ID: str, name: str, string_const: str, num_years: int):
    return {
        lgmvf.LG_TPL_CONTRACT_ID: ID,
        lgmvf.LG_TPL_CONTRACT_NAME: name,
        lgmvf.LG_TPL_CONTRACT_STR_CONST: string_const,
        lgmvf.LG_TPL_CONTRACT_CUSTOM: False,
        lgmvf.LG_TPL_CONTRACT_COST: [0] * num_years,
    }


#######################################################################################################
#                                                                                                     #
#                                            Results                                                  #
#                                                                                                     #
#######################################################################################################


def LG_init_result_dict_by_level(modvars):
    supply_chain_level_records = modvars[lgmvt.LG_SUPPLY_CHAIN_LEVEL_RECORDS_TAG]
    num_supply_chain_levels = lgmvu.get_LG_num_supply_chain_levels(supply_chain_level_records)
    first_year_mv = modvars[pjmvt.PJN_FirstYearTag]
    final_year_mv = modvars[pjmvt.PJN_FinalYearTag]
    num_years = final_year_mv - first_year_mv + 1

    return LG_init_dict_by_level(0, num_supply_chain_levels, np.full(num_years, 0.0))


def LG_init_result_dict_by_warehouse(modvars):
    disag_level = modvars[lgmvt.LG_DISAGGREGATION_LEVEL_TAG]
    warehouse_records = modvars[lgmvt.LG_WAREHOUSE_RECORDS_TAG]
    first_year_mv = modvars[pjmvt.PJN_FirstYearTag]
    final_year_mv = modvars[pjmvt.PJN_FinalYearTag]

    warehouse_records_to_include = lgmvu.get_LG_warehouse_records_up_to_disag_level(warehouse_records, disag_level)
    num_years = final_year_mv - first_year_mv + 1

    return LG_init_dict_by_warehouse(warehouse_records_to_include, np.full(num_years, 0.0))


def LG_init_result_dict_by_warehouse_by_level(modvars):
    disag_level = modvars[lgmvt.LG_DISAGGREGATION_LEVEL_TAG]
    supply_chain_level_records = modvars[lgmvt.LG_SUPPLY_CHAIN_LEVEL_RECORDS_TAG]
    warehouse_records = modvars[lgmvt.LG_WAREHOUSE_RECORDS_TAG]
    first_year_mv = modvars[pjmvt.PJN_FirstYearTag]
    final_year_mv = modvars[pjmvt.PJN_FinalYearTag]

    num_supply_chain_levels = lgmvu.get_LG_num_supply_chain_levels(supply_chain_level_records)
    warehouse_records_to_include = lgmvu.get_LG_warehouse_records_for_disag_level(warehouse_records, disag_level)
    num_years = final_year_mv - first_year_mv + 1

    return LG_init_dict_by_warehouse_by_level(
        warehouse_records_to_include, num_supply_chain_levels, np.full(num_years, 0.0)
    )


def LG_init_result_dict_by_vehicle_by_level(modvars):
    vehicle_records = modvars[lgmvt.LG_VEHICLE_TYPE_RECORDS_TAG]
    return {
        vehicle_record.get(lgmvf.LG_VEHICLE_TYPE_ID): LG_init_result_dict_by_level(modvars)
        for vehicle_record in vehicle_records
    }


def LG_init_result_dict_by_vehicle_by_warehouse(modvars):
    vehicle_records = modvars[lgmvt.LG_VEHICLE_TYPE_RECORDS_TAG]
    return {
        vehicle_record.get(lgmvf.LG_VEHICLE_TYPE_ID): LG_init_result_dict_by_warehouse(modvars)
        for vehicle_record in vehicle_records
    }


def LG_init_result_dict_by_vehicle_by_warehouse_by_level(modvars):
    vehicle_records = modvars[lgmvt.LG_VEHICLE_TYPE_RECORDS_TAG]
    return {
        vehicle_record.get(lgmvf.LG_VEHICLE_TYPE_ID): LG_init_result_dict_by_warehouse_by_level(modvars)
        for vehicle_record in vehicle_records
    }


def LG_init_result_dict_by_worker_type_by_level(modvars):
    worker_records = modvars[lgmvt.LG_WORKER_TYPE_RECORDS_TAG]
    return {
        worker_record.get(lgmvf.LG_WORKER_TYPE_ID): LG_init_result_dict_by_level(modvars)
        for worker_record in worker_records
    }


def LG_init_result_dict_by_worker_type_by_warehouse(modvars):
    worker_records = modvars[lgmvt.LG_WORKER_TYPE_RECORDS_TAG]
    return {
        worker_record.get(lgmvf.LG_WORKER_TYPE_ID): LG_init_result_dict_by_warehouse(modvars)
        for worker_record in worker_records
    }


def LG_init_result_dict_by_worker_type_by_warehouse_by_level(modvars):
    worker_records = modvars[lgmvt.LG_WORKER_TYPE_RECORDS_TAG]
    return {
        worker_record.get(lgmvf.LG_WORKER_TYPE_ID): LG_init_result_dict_by_warehouse_by_level(modvars)
        for worker_record in worker_records
    }


def LG_init_result_dict_by_cold_chain_by_level(modvars):
    cold_chain_records = modvars[lgmvt.LG_COLD_CHAIN_RECORDS_TAG]
    return {
        cold_chain_record.get(lgmvf.LG_COLD_CHAIN_ID): LG_init_result_dict_by_level(modvars)
        for cold_chain_record in cold_chain_records
    }


def LG_init_result_dict_by_cold_chain_by_warehouse(modvars):
    cold_chain_records = modvars[lgmvt.LG_COLD_CHAIN_RECORDS_TAG]
    return {
        cold_chain_record.get(lgmvf.LG_COLD_CHAIN_ID): LG_init_result_dict_by_warehouse(modvars)
        for cold_chain_record in cold_chain_records
    }


def LG_init_result_dict_by_cold_chain_by_warehouse_by_level(modvars):
    cold_chain_records = modvars[lgmvt.LG_COLD_CHAIN_RECORDS_TAG]
    return {
        cold_chain_record.get(lgmvf.LG_COLD_CHAIN_ID): LG_init_result_dict_by_warehouse_by_level(modvars)
        for cold_chain_record in cold_chain_records
    }


def LG_init_quantity_source_drug_supply_year_arr(num_drugs_supplies: int, num_years: int, value=0.0):
    return np.full((lgc.LG_NUM_QUANTITY_SOURCES, num_drugs_supplies, num_years), value, gbc.GB_CALC_FLOAT_TYPE)
