import pandas as pnd
import gempipe


from ..commons import get_biomass_dict
from ..commons import apply_medium_given_column
from ..commons import verify_growth

from .gapfillutils import get_repository_nogenes
from .gapfillutils import import_from_universe



def gapfill_on_media(logger, model, universe, expcon, media, varprec, exclude_orphans):
    
    
    
    # get biomass precursors to gap-fill: 
    biomass_mids = []
    for value in get_biomass_dict().values(): biomass_mids = biomass_mids + value
    
    
    # check if requested (always)
    df_B = pnd.DataFrame()
    
    
    # prepare sheet for excel output
    df_B['name'] = None
    df_B['cond'] = None
    df_B['coeff'] = None
    for mid in biomass_mids:
        df_B.loc[mid, 'name'] = universe.metabolites.get_by_id(mid).name
        df_B.loc[mid, 'coeff'] = 0.01
        if mid in varprec.keys():
            df_B.loc[mid, 'cond'] = f'{varprec[mid]}'
            if mid not in [m.id for m in  model.reactions.Biomass.reactants]:  
                df_B.loc[mid, 'coeff'] = 'removed'
        else:  # biomass precursor is NOT variable (it's mandatory)
            df_B.loc[mid, 'cond'] = '/'
            
    
    # get involved media:
    if media == '-':
        logger.info(f"No media provided: gap-filling will be skipped.")
        return df_B
    media = media.split(',')
    # at least 1 medium must exist:
    if any([i in expcon['media'].columns for i in media])==False:
        logger.error(f"None of the provided media IDs exist. Available media are {list(expcon['media'].columns)}.")
        return 1
        
        
    # get the repository of reactions:
    repository_nogenes = get_repository_nogenes(logger, universe, exclude_orphans)
    
    
    logger.info(f"Gap-filling for biomass on {len(media)} media...")
    for medium in media: 
        if medium not in expcon['media'].columns:
            logger.info(f"Medium '{medium}' does not exists and will be ignored.")
            continue
        # create dedicated column on the excel output
        df_B[f'{medium}'] = None
        logger.debug(f"Gap-filling on medium '{medium}'...")
                    
            
        # apply medium both on universe and model:
        response = apply_medium_given_column(logger, repository_nogenes, medium, expcon['media'][medium])
        if response == 1: return 1
        if not verify_growth(repository_nogenes):
            logger.error(f"Medium '{medium}' does not support growth of universe.")
            return 1
        
        response = apply_medium_given_column(logger, model, medium, expcon['media'][medium])
        if response == 1: return 1
        if verify_growth(model):
            logger.info(f"No need to gapfill model on medium '{medium}'.")
            continue


        # launch gap-filling separately for each biomass precursor:
        for mid in biomass_mids:
            # skip conditional precursors: 
            if mid in [m.id for m in model.reactions.Biomass.reactants]:
            
                # save time if it can already be synthesized
                if gempipe.can_synth(model, mid)[0]:
                    df_B.loc[mid, f'{medium}'] = '/'
                    logger.debug(f"Gap-filled 0 reactions on medium '{medium}' for '{mid}': [].")
                    continue   # save time!

                    
                # otherwise perform the actual gap-fill:    
                #minflux = get_optthr()
                minflux = 0.1
                suggested_rids = gempipe.perform_gapfilling(model, repository_nogenes, mid, nsol=1, minflux=minflux, boost=True, verbose=False)
                if suggested_rids == None:
                    logger.error(f"The gap-filling problem seems too hard for '{mid}' on medium '{medium}': should '{mid}' be included in '{medium}'?")
                    return 1
                
                df_B.loc[mid, f'{medium}'] = '; '.join([f'+{i}' for i in suggested_rids]) 
                logger.debug(f"Gap-filled {len(suggested_rids)} reactions on medium '{medium}' for '{mid}': {suggested_rids}.")
                for rid in suggested_rids:
                    import_from_universe(model, repository_nogenes, rid, gpr='')
                
                
    return df_B

