import json
import urllib3
from concurrent.futures import as_completed
from requests_futures.sessions import FuturesSession
import requests
import pkgutil
from loguru import logger
import time

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def get_class_lab_instance_type(url,headers,class_name):
    try:
        logger.info(f'Attempting to get the instance type id by code: {class_name}')
        resp = requests.get(f'{url}/api/library/instance-types?code={class_name}',headers=headers,verify=False)
    except Exception as e:
        logger.error(f'Something went wrong: {e}')
    if "200" in str(resp):
        logger.info(f'Instance type found')
        logger.info(f'ID: {resp.json()["instanceTypes"][0]["id"]}')
        instance_type = resp.json()["instanceTypes"][0]
        return(instance_type)
    else:
        logger.error(f'Instance type not found')

def get_class_layout_id(url,headers,custom_options,instance_type_map):
    endpoint = "/api/library/layouts"
    for l in instance_type_map["instanceTypeLayouts"]:
        try:
            logger.info(f'Attempting to get the layout with the ID of: {l["id"]}')
            resp = requests.get(f'{url}{endpoint}/{l["id"]}', headers=headers, verify=False)
        except Exception as e:
            logger.error(f'Something went horribly wrong here: {e}')
        if "200" in str(resp):
            logger.info(f'Layout found')
            logger.info(f'ID: {resp.json()["instanceTypeLayout"]["id"]}')
            logger.info(f'Version: {resp.json()["instanceTypeLayout"]["instanceVersion"]}')
            logger.info('Comparing to class version...')
            if resp.json()["instanceTypeLayout"]["instanceVersion"] == custom_options["class_version"]:
                logger.info(f'Version match found')
                layout_id = resp.json()["instanceTypeLayout"]["id"]
                return(layout_id)
            else:
                logger.info(f'Version mismatch. Skipping...')

def get_morpheus_terraform_plan_id(url,headers):
    """
    The get_morpheus_terraform_plan_id function is used to get the id of the Morpheus Terraform plan.
    This function returns a single integer value which represents the ID of the plan.
    
    :param url: Specify the morpheus api url
    :param headers: Pass the token generated by morpheus
    :return: The id of the morpheus terraform plan
    :doc-author: Trelent
    """
    endpoint = "/api/service-plans?phrase=Terraform"
    try:
        logger.info(f'Attempting to get the Morpheus Terraform plan id.')
        resp = requests.get(f'{url}{endpoint}', headers=headers, verify=False).json()
    except Exception as e:
        logger.error(f'Something went horribly wrong {e}')
    return(resp["servicePlans"][0]["id"])

def get_instance_provisioning_payload(class_version,zone_id,instance_name,site_id,instance_type,instance_type_code,layout_id,plan_id,template_parameters):
    """
    The get_instance_provisioning_payload function takes the provided variables and loads a template file that contains
    the payload for the instance provisioning API call. The function then updates the template with all of the provided 
    variables, and returns it as a JSON object.
    
    :param zone_id: Identify the zone in which to create the instance
    :param instance_name: Name the instance
    :param site_id: Determine the site to which the instance will be attached
    :param instance_type: Determine the instance type code for the payload
    :param instance_type_code: Determine the type of instance to be provisioned
    :param layout_id: Specify the layout of the instance
    :param plan_id: Determine the instance type
    :param template_parameters: Pass in the parameters that are needed to provision an instance
    :return: A payload template that can be used to provision an instance
    :doc-author: Trelent
    """
    try:
        logger.info(f'Attempting to load the payload template file')
        f = pkgutil.get_data(__name__, 'template_files/provisioning_payload.json')
        f = json.loads(f)
    except Exception as e:
        logger.error(f'Something has gone awry. {e}')
    try:
        logger.info(f'Updating the payload template with the provided variables')
        f["zoneId"] = zone_id
        f["instance"]["name"] = instance_name
        f["instance"]["site"]["id"] = site_id
        f["instance"]["type"] = instance_type
        f["instance"]["instanceType"]["code"] = instance_type_code
        f["instance"]["layout"]["id"] = layout_id
        f["instance"]["plan"]["id"] = plan_id
        f["config"]["templateParameter"] = template_parameters
    except Exception as e:
        logger.error(f'Terrible failure herein {e}')
    return(f)

def get_instance(url,headers,instance_id):
    """
    The get_instance function is used to get the details of a specific instance. It does this by making an API call
    to the Morpheus API, and then returning the response as a JSON object.
    
    :param url: Specify the morpheus api url
    :param headers: Pass the token generated by morpheus
    :param instance_id: Pass the id of the instance to get
    :return: A JSON object containing the details of the instance
    :doc-author: Trelent
    """
    endpoint = "/api/instances"
    try:
        logger.info(f'Attempting to get the instance with the ID of: {instance_id}')
        resp = requests.get(f'{url}{endpoint}/{instance_id}', headers=headers, verify=False)
    except Exception as e:
        logger.error(f'Something went horribly wrong {e}')
        return(e)
    if "200" in str(resp):
        logger.info(f'Instance found')
        return(resp.json()["instance"])
    else:
        logger.error(f'Instance not found')

def gen_instance_names(instance_map):
    start = 0
    end = instance_map["customOptions"]["seatCount"]
    logger.info(f'Generating a list of instance names')
    list = []
    while start < end:
        start += 1
        list.append(f'{instance_map["customOptions"]["class_name"][0:3]}-{instance_map["customOptions"]["trainingZone"].split(",")[1][0:2]}{instance_map["customOptions"]["trainingZone"].split(",")[1].split("-")[1][0:1]}{instance_map["customOptions"]["trainingZone"].split(",")[1][-1]}-{instance_map["customOptions"]["lab_name"]}{start:02d}'.format(start))
    return(list)

def get_morpheus_terraform_inputs(morpheus_custom_options):
    """
    The get_lab_terraform_inputs function takes the provided Morpheus custom options and parses them to determine which template parameters need to be filled in. It then fills in the appropriate values for those parameters and returns a dictionary of all of the template parameters with their corresponding values.
    
    :param morpheus_custom_options: Pass in the custom options that have been provided by the user
    :return: A dictionary of the key value pairs that should be used for the lab
    :doc-author: Trelent
    """
    # Set the class version
    class_version = morpheus_custom_options["class_version"]

    # Validate the class type and import the correct file template for the template parameters to fill in
    if "administration" in morpheus_custom_options["class_name"]:
        logger.info(f'Administration class selected. Importing admin_class_tf_vars.json')
        f = pkgutil.get_data(__name__, 'template_files/admin_class_tf_vars.json')
        f = json.loads(f)
    elif "installation" in morpheus_custom_options["class_name"]:
        logger.info(f'Installation class selected. Importing instal_class_tf_vars.json')
        f = pkgutil.get_data(__name__, 'template_files/install_class_tf_vars.json')
        f = json.loads(f)
    elif 'automation' in morpheus_custom_options["class_name"]:
        logger.info(f'Automation class selected. Importing automation_class_tf_vars.json')
        f = pkgutil.get_data(__name__, 'template_files/automation_class_tf_vars.json')
        f = json.loads(f)
    elif 'troubleshooting' in morpheus_custom_options["class_name"]:
        logger.info(f'Troubleshooting class selected. Importing troubleshooting_class_tf_vars.json')
        f = pkgutil.get_data(__name__, 'template_files/troubleshooting_class_tf_vars.json')
        f = json.loads(f)
    terraform_inputs = {}
    # Parse the key value pairs of the provided Morpheus custom options
    for k, v in morpheus_custom_options.items():
        logger.info(f'Checking for a match on the option type: {k}')
        try: 
            if k in f:
                logger.info(f'Found {k}, updating with a value of {v}')
                update = {k: v}
                terraform_inputs.update(update)
            else:
                logger.info(f'{k} not found in the template. Skipping it.')
        except Exception as e:
            logger.error(f'Something went wrong {e}')
    for k, v in f.items():
        try:
            if v :
                logger.info(f'Item {k} with a value of {v} discovered. Adding it to the payload.')
                update = {k: v}
                terraform_inputs.update(update)
            else:
                logger.info(f'{k} does not have a default value in the template. Skipping it')
        except Exception as e:
            logger.error(f'Something went wrong: {e}')
    return(terraform_inputs)

def extract_json_content(text):
    start_token = "----json_object_start----"
    end_token = "----json_object_end----"
    
    start_index = text.find(start_token)
    end_index = text.find(end_token)
    
    if start_index == -1 or end_index == -1 or start_index >= end_index:
        return None  # Return None if the start or end token is not found, or if start comes after end

    return text[start_index + len(start_token):end_index].strip()