from loguru import logger
from SpectrumCommon.Const.GB import *
from SpectrumCommon.Const.PJ import *
from SpectrumCommon.Const.AM.AMTags import AM_FirstYearOfEpidemicTag
from SpectrumCommon.Modvars.GB.GBCreateProjection import GB_CreateProjection
from SpectrumCommon.Modvars.GB.GBDefs import createProjectionParams
from SpectrumCommon.Modvars.DP.DPUpdateModvars import DP_UpdateModvars
from SpectrumCommon.Modvars.AM.AMUpdateModvars import AM_UpdateModvars
from SpectrumCommon.Modvars.CS.CSUpdateModvars import CS_UpdateModvars, CS_GSKModeTag, CS_PreUpdateModvars
from SpectrumCommon.Modvars.TB.TBUpdateModvars import TB_UpdateModvars, TB_PreUpdateModvars
from SpectrumCommon.Modvars.IC.ICUpdateModvars import IC_UpdateModvars
from SpectrumCommon.Modvars.BG.BGUpdateModvars import BG_UpdateModvars
from SpectrumCommon.Modvars.IS.ISUpdateModvars import IS_UpdateModvars
from SpectrumCommon.Modvars.PC.PCUpdateModvars import PC_UpdateModvars

def GB_UpdateModvars(projection):
    '''
        Updates Modvars (MVs) for a projection that have changed in subsequent Projection Manager releases.

            Parameters:
                projection (dict): All MVs in the projection (before being updated).

            Returns:
                projection (dict): All MVs in the projection (after being updated).

    '''

    module_switch = {
        # GB_GBCode : None,
        # GB_GBCode : None,
        GB_DPCode : DP_UpdateModvars,
        # GB_IVCode : None,
        # GB_FPCode : None,
        GB_AMCode : AM_UpdateModvars,
        # GB_RPCode : None,
        # GB_HVCode : None,
        GB_CSCode : CS_UpdateModvars,
        # GB_IHCode : None,
        # GB_HWCode : None,
        # GB_BACode : None,
        GB_ICCode : IC_UpdateModvars,
        GB_ISCode : IS_UpdateModvars,
        # GB_FSCode : None,
        GB_PCCode : PC_UpdateModvars,
        # GB_LGCode : None,
        GB_TBCode : TB_UpdateModvars,
        GB_BGCode : BG_UpdateModvars,
        # GB_HSCode : None,
        # GB_RNCode : None,
        # GB_GVCode : None,
        # GB_HFCode : None,
        # GB_NCCode : None,
        # GB_TICode : None,
        # GB_MACode : None,
        # GB_GCCode : None,
        # GB_HACode : None,
        # GB_MTCode : None,
        # GB_SICode : None,
        # GB_GTCode : None,
        # GB_PJCode : PJ_UpdateModvars,
    }

    module_pre_updater_switch = {
        GB_TBCode : TB_PreUpdateModvars,
        GB_CSCode : CS_PreUpdateModvars
    }
 
    # Add new modvars and updating
    create_params = createProjectionParams()
    
    create_params.fileName = projection[PJN_TitleTag]
    create_params.country = projection[PJN_ISO3AlphaTag]
    create_params.firstYear = projection[PJN_FirstYearTag]
    create_params.finalYear = projection[PJN_FinalYearTag]
    create_params.modules = projection[PJN_ModulesTag]
    create_params.extra = {
        GB_IHT_ON                 : projection.get(GB_IHTOnTag , False),
        GB_TB_COSTING_ON          : projection.get(GB_TBCostingOnTag , False),
        GB_LIST_COSTING_ON        : projection.get(GB_LCOnTag , False),
        GB_GSKMode                : projection.get(GB_GSKModeTag, projection.get(CS_GSKModeTag, False)),
        # GB_RAPID_SECTORS_ON       : projection.get(GB_RAPIDSectorsOnTag, RP_init_sector_list()),
        GB_TB_ImpactStatistical   : projection.get(GB_TBImpactStatisticalTag , False),
        GB_TB_ImpactDynamical     : projection.get(GB_TBImpactDynamicalTag , False),
        GB_Extra_SubnatCode       : projection.get(PJN_SubNationalCodeTag, 0),
        GB_Extra_subnatName       : projection.get(PJN_SubNationalNameTag, ''),
        GB_Extra_projection_title : projection.get(PJN_TitleTag, ''),
        GB_Extra_Author           : projection.get(PJN_AuthorTag, ''),
        GB_Extra_organization     : projection.get(PJN_OrganizationTag, ''),
        GB_Extra_notes            : projection.get(PJN_NotesTag, ''),
        GB_Extra_appID            : projection.get(PJN_AppIDTag, ''),
        GB_Extra_plantype         : projection.get(PJN_IHTPlanTypeTag, ''),
        GB_Extra_readonly         : projection.get(PJN_ReadOnlyTag, ''),
        
         # Need to use the correct epidemic start year for sex ratio modvar
        GB_Extra_epidemicStartYr  : projection.get(AM_FirstYearOfEpidemicTag, 1980),
    }

    # Contains all the new MVs.
    created_projection = GB_CreateProjection(create_params)
    
    # Make sure all the modules in the projection we just created are in PJN_ModulesTag. If new modules get added for existing
    # projections, they won't be in 'projection[PJN_ModulesTag]' yet.
    projection[PJN_ModulesTag] = []
    for module in created_projection[PJN_ModulesTag]:
        projection[PJN_ModulesTag].append(module)

    if projection[PJN_VersionTag][0] == '0':
        return created_projection
    
    modules = projection[PJN_ModulesTag]
    
    # Pre-update modvars that don't exist in the projection yet
    for md in modules:
        if GB_MOD_STR[md] in module_pre_updater_switch:
            logger.debug(f'PreUpdating {GB_MOD_STR[md]}')
            projection = module_pre_updater_switch[GB_MOD_STR[md]](projection, created_projection)  

    # add any missing modvars from created_projection to projection  
    for tag in created_projection:
        if tag not in projection:
            projection.update({tag: created_projection[tag]})

    # Update all meta modvars
    for tag in projection:
        if '_meta_' in tag.lower():
            if tag in created_projection:
                projection[tag] = created_projection[tag]

    # Update and delete old modvars
    for md in modules:
        if GB_MOD_STR[md] in module_switch:
            logger.debug(f'Updating {GB_MOD_STR[md]}')
            projection = module_switch[GB_MOD_STR[md]](projection, created_projection)  

    # Remove any old tags that are not found in a newly created projection, preserve pseudo-modules that are dynamically added
    projection = {tag:projection[tag] for tag in projection if ((tag in created_projection) or (tag[1:3] in GB_PSEUDO_MOD_ID))} 

    # Once everything is updated, update the version to the latest version
    projection[PJN_VersionTag] = GB_PM_Version
    return projection