import os
import pickle


import cobra
import gempipe


from ..commons import force_id_on_sbml
from ..commons import log_metrics
from ..commons import get_db
from ..commons import introduce_biomass
from ..commons import write_excel_model
from ..commons import show_contributions

from .introduce import introduce_metabolites
from .introduce import introduce_reactions
from .introduce import introduce_transporters
from .introduce import introduce_sinks_demands

from .annotation import translate_annotate_genes
from .annotation import set_up_groups

from .completeness import check_completeness

from ..runsims.simplegrowth import grow_on_media
from ..runsims.precursors import precursors_on_media
from ..runsims.biosynth import biosynthesis_on_media




def main(args, logger):
    
    
    # adjust out folder path                      
    while args.outdir.endswith('/'):              
        args.outdir = args.outdir[:-1]
    os.makedirs(f'{args.outdir}/', exist_ok=True)
    
    
    # check compatibility of input parameters
    if args.progress==False and args.module==True: 
        logger.error(f"You cannot ask --module without --progress (see --help).")
        return 1
    if args.progress==False and args.focus!='-':
        logger.error(f"You cannot ask --focus without --progress (see --help).")
        return 1
    if args.progress==False and args.zeroes==True:
        logger.error(f"You cannot ask --zeroes without --progress (see --help).")
        return 1
    
    
    # check 'goodbefore' and 'onlyauthor' params
    if args.goodbefore == '-' and args.onlyauthor != '-':
        logger.error(f"--onlyauthor must be used in conjunction with --goodbefore.")
        return 1
    if   args.goodbefore == '-': args.goodbefore = [None, None, None]
    elif len(args.goodbefore.split('-')) != 3: 
        logger.error(f"Invalid syntax detected for --goodbefore.")
        return 1
    else:
        args.goodbefore = args.goodbefore.split('-')
        if args.goodbefore[0] == 'None': args.goodbefore[0] = None
        if args.goodbefore[1] == 'None': args.goodbefore[1] = None
        if args.goodbefore[2] == 'None': args.goodbefore[2] = None
    if args.onlyauthor == '-': args.onlyauthor = None
    
    
    # check and extract the required 'gsrap.maps' file
    if os.path.exists(f'{args.inmaps}') == False:
        logger.error(f"File 'gsrap.maps' not found at {args.inmaps}.")
        return 1
    try: 
        with open(f'{args.inmaps}', 'rb') as f:
            inmaps = pickle.load(f)  
    except: 
        logger.error(f"Provided file {args.inmaps} has an incorrect format.")
        return 1
    idcollection_dict = inmaps['idcollection_dict']
    summary_dict = inmaps['summary_dict']
    keggc_to_bigg = inmaps['keggc_to_bigg']
    keggr_to_bigg = inmaps['keggr_to_bigg']
    
    
    # download database and check structure
    db = get_db(logger)
    if type(db)==int: return 1

    # show simple statistics of contributions
    show_contributions(logger, db)
                                    
        
    
    ###### RECONSTRUCTION
    # create the model
    universe = cobra.Model('newuni')   
    
    # introduce M / R / T
    universe = introduce_metabolites(logger, db, universe, idcollection_dict, keggc_to_bigg, args.goodbefore[0], args.onlyauthor)
    if type(universe)==int: return 1
    universe = introduce_reactions(logger, db, universe, idcollection_dict, keggr_to_bigg, args.goodbefore[1], args.onlyauthor)
    if type(universe)==int: return 1
    universe = introduce_transporters(logger, db, universe, idcollection_dict, keggr_to_bigg, args.goodbefore[2], args.onlyauthor)
    if type(universe)==int: return 1

    # introduce sinks / demands (exchanges where included during T)
    universe = introduce_sinks_demands(logger, universe)
    if type(universe)==int: return 1

    # introducce biomass
    universe = introduce_biomass(logger, db, universe)
    if type(universe)==int: return 1



    ###### ANNOTATION
    # translate Gs to symbols and annotate them (EC, COG, GO, ...)
    universe = translate_annotate_genes(logger, universe, idcollection_dict)
    if type(universe)==int: return 1

    # introduce collectionas (groups of Rs as maps/modules)
    universe = set_up_groups(logger, universe, idcollection_dict)
    if type(universe)==int: return 1

    
    
    ###### CHECKS
    # check universe completness
    response = check_completeness(logger, universe, args.progress, args.module, args.focus, args.eggnog, args.zeroes, idcollection_dict, summary_dict)
    if response==1: return 1

    # check growth on minmal media
    df_G = grow_on_media(logger, universe, None, None, '-')
    if type(df_G)==int: return 1
    
    # check blocked biomass precursors
    df_E = precursors_on_media(logger, universe, universe, None, None, None, args.precursors)
    if type(df_E)==int: return 1

    # check blocked metabolites / dead-ends
    df_S = biosynthesis_on_media(logger, universe, None, None, args.biosynth)
    if type(df_S)==int: return 1


    
    ###### POLISHING
    # reset growth environment befor saving the model
    gempipe.reset_growth_env(universe)



    # output the universe
    cobra.io.save_json_model(universe, f'{args.outdir}/newuni.json')
    logger.info(f"'{args.outdir}/newuni.json' created!")
    cobra.io.write_sbml_model(universe, f'{args.outdir}/newuni.xml')   # groups are saved only to SBML 
    logger.info(f"'{args.outdir}/newuni.xml' created!")
    force_id_on_sbml(f'{args.outdir}/newuni.xml', 'newuni')   # force introduction of the 'id=""' field
    write_excel_model(universe, f'{args.outdir}/newuni.parsedb.xlsx', df_E, None, None, df_S)  
    logger.info(f"'{args.outdir}/newuni.parsedb.xlsx' created!")
    log_metrics(logger, universe, outmode='uni_features')


      
    return 0