import shutil, os, csv
from workflow.log import logcolor

# Config Validation sections
# This should get updated as the workflow is built out
VALID_GENERAL_OPTS = ["dry_run", "order", "input_fastq_path", "input_manifest", "output_path", "threads"]
VALID_STEP_OPTS = ["software","args"]

def validate_manifest_files(config,logger):
    manifest_path = config["GENERAL"]["input_manifest"].replace('"',"")    
    logger.info(f"{logcolor.SUCCESS}--> Manifest check successful!{logcolor.ENDC}")
    pass #TODO


def validate_config_options(config,logger):
    if "GENERAL" not in config: # check for general section
        logger.error(f"{logcolor.ERROR}--> Config check failed!{logcolor.ENDC}")
        logger.error(f"It looks like your config file is missing a {logcolor.REFERENCE}[GENERAL]{logcolor.ENDC} section. Please refer to the README.md for more help.")
        exit(2)

    for opt in config["GENERAL"]: # check to make sure there aren't unknown opts in general
        if opt not in VALID_GENERAL_OPTS:
            logger.error(f"{logcolor.ERROR}--> Config check failed!{logcolor.ENDC}")
            logger.error(f"The option {logcolor.REFERENCE}{opt}{logcolor.ENDC} is not a valid config option in {logcolor.REFERENCE}[GENERAL]{logcolor.ENDC}. Please refer to the README.md for more help.")
            exit(2)
    for opt in VALID_GENERAL_OPTS: # check to make sure general has everything that is required
        if opt not in config["GENERAL"]:
            logger.error(f"{logcolor.ERROR}--> Config check failed!{logcolor.ENDC}")
            logger.error(f"Config section {logcolor.REFERENCE}[GENERAL]{logcolor.ENDC} is missing the {logcolor.REFERENCE}{opt}{logcolor.ENDC} option. Please refer to the README.md for more help.")
            exit(2)

    for section in config: # check each software step section
        if section in ["GENERAL", "DEFAULT"]:
            pass
        else:
            for opt in config[section]: # make sure it doesn't include extra opts
                if opt not in VALID_STEP_OPTS:
                    logger.error(f"{logcolor.ERROR}--> Config check failed!{logcolor.ENDC}")
                    logger.error(f"The option {logcolor.REFERENCE}{opt}{logcolor.ENDC} is not a valid config option in {logcolor.REFERENCE}{section}{logcolor.ENDC}. Please refer to the README.md for more help.")
                    exit(2)
            for opt in VALID_STEP_OPTS: # make sure it includes all required opts
                if opt not in config[section]:
                    if opt != "mode":		# hacky, but temporary (TODO)
                        logger.error(f"{logcolor.ERROR}--> Config check failed!{logcolor.ENDC}")
                        logger.error(f"Config section {logcolor.REFERENCE}{section}{logcolor.ENDC} is missing the {logcolor.REFERENCE}{opt}{logcolor.ENDC} option. Please refer to the README.md for more help.")
                        exit(2)

    logger.info(f"{logcolor.SUCCESS}--> Config check successful!{logcolor.ENDC}")

def validate_args(config, software_dictionary,logger):
    # General/output_path should not already exist
    output_path = config["GENERAL"]['output_path']
    if os.path.exists(output_path.replace('"',"")):
        logger.error(f"{logcolor.ERROR}--> Argument check failed!{logcolor.ENDC}")
        logger.error(f"Output path {logcolor.REFERENCE}{output_path}{logcolor.ENDC} already exists. Please double check your config.")
        exit(2)

    # General/input_manifest SHOULD exist
    input_fastq_path = config["GENERAL"]['input_fastq_path']
    if not os.path.exists(input_fastq_path.replace('"',"")):
        logger.error(f"{logcolor.ERROR}--> Argument check failed!{logcolor.ENDC}")
        logger.error(f"Input path {logcolor.REFERENCE}{input_fastq_path}{logcolor.ENDC} does not exist. Please double check your config.")
        exit(2)

    
    # General/input_manifest SHOULD exist
    input_manifest = config["GENERAL"]['input_manifest']
    if not os.path.exists(input_manifest.replace('"',"")):
        logger.error(f"{logcolor.ERROR}--> Argument check failed!{logcolor.ENDC}")
        logger.error(f"Input manifest {logcolor.REFERENCE}{input_manifest}{logcolor.ENDC} does not exist. Please double check your config.")
        exit(2)

    # General/dry_run should be a boolean
    dry_run = config["GENERAL"]['dry_run']
    if dry_run not in [True, False, "True", "False"]:
        logger.error(f"{logcolor.ERROR}--> Argument check failed!{logcolor.ENDC}")
        logger.error(f"'dry_run' should be a True/False value, not {logcolor.REFERENCE}{dry_run}{logcolor.ENDC}. Please double check your config.")
        exit(2)

    # General/order should only contain names of other sections
    for section in config["GENERAL"]["order"].split():
        if section not in config:
            logger.error(f"{logcolor.ERROR}--> Argument check failed!{logcolor.ENDC}")
            logger.error(f"Step section {logcolor.REFERENCE}{section}{logcolor.ENDC} is in your {logcolor.REFERENCE}order{logcolor.ENDC} option, but is not configured. Please double check your config.")
            exit(2)

    # Each section/software should be in the software_dict
    for section in config["GENERAL"]["order"].split():
        if config[section]["software"] not in software_dictionary:
            failed_software = config[section]["software"]
            logger.error(f"{logcolor.ERROR}--> Argument check failed!{logcolor.ENDC}")
            logger.error(f"Software {logcolor.REFERENCE}{failed_software}{logcolor.ENDC} in section {logcolor.REFERENCE}{section}{logcolor.ENDC} is not valid. Please double check your config.")
            exit(2)

    logger.info(f"{logcolor.SUCCESS}--> Argument check successful!{logcolor.ENDC}")

def validate_additional_args(stepname, unneeded_args, additional_step_args,logger):
    for arg in unneeded_args:
        if f"{arg} " in additional_step_args:
            logger.error(f"{logcolor.ERROR}--> Additional Argument error!{logcolor.ENDC}")
            logger.error(f"It looks like you are including a {logcolor.REFERENCE}{arg}{logcolor.ENDC} arguement in your config step {logcolor.REFERENCE}{stepname}{logcolor.ENDC}. This arguement is generated, and you don't need to supply it.")
            exit(2)

def validate_env(software_steps,logger):
    for step in software_steps:
        if shutil.which(step.software_name) != None:
            pass
        else: 
            logger.error(f"{logcolor.ERROR}--> Environment check failed!{logcolor.ENDC}")
            logger.error(f"It looks like {logcolor.REFERENCE}{step.software_name}{logcolor.ENDC} not in your path. You might need to load a module, or install the software.")
            exit(2)
    logger.info(f"{logcolor.SUCCESS}--> Environment check successful!{logcolor.ENDC}")
