import json
import yaml
import os
import subprocess

def get_filepath(filename):
    """
    Input: filename (a string representing a file name)
    Output: Returns the absolute file path of the given filename if it exists; otherwise, 
    returns None.
    Purpose: This function takes a filename and returns its absolute path if the file exists.
    """
    file_path = os.path.abspath(filename)
    if os.path.exists(file_path):
        return file_path
    else:
        return None

def create_crd(outputDir):
    data = {
    "apiVersion": "apiextensions.k8s.io/v1",
    "kind": "CustomResourceDefinition",
    "metadata": {
        "name": "securitychains.kopf.dev"
    },
    "spec": {
        "scope": "Namespaced",
        "group": "kopf.dev",
        "names": {
            "kind": "SecurityChain",
            "plural": "securitychains",
            "singular": "securitychain",
            "shortNames": ["scs", "sc"]
        },
        "versions": [
            {
                "name": "v1",
                "served": True,
                "storage": True,
                "schema": {
                    "openAPIV3Schema": {
                        "type": "object",
                        "properties": {
                            "spec": {
                                "type": "object",
                                "x-kubernetes-preserve-unknown-fields": True
                            },
                            "status": {
                                "type": "object",
                                "x-kubernetes-preserve-unknown-fields": True
                                }
                            }
                        }
                    }
                }
            ]
        }
    }

    with open(os.path.join(outputDir, "crd.yaml"), "w") as file:
        yaml.dump(data, file, default_flow_style=False)


def toYaml(outputDir):
    """
    Convert data from 'requirements.json' to a custom YAML object and write it to 'obj.yaml'.
    Output: Generates a YAML file named "obj.yaml" in the current directory.

    Purpose:
    This function reads data from a JSON file named "requirements.json" and converts it into a custom YAML object format.
    It involves mapping information from the JSON data to a specific structure in the YAML.
    The conversion includes mapping data based on 'requirements_mapping.json'.

    Exceptions:
    - If there's an error during the conversion process, it will be captured and returned as a string.

    Returns:
    - List of missing requirements: Requirements that could not be mapped and are not supported.
      ```
      The JSON data is processed, and each requirement is mapped to a 'security_function' and added to the 'securityFunctions' list.
      Some fields like 'image', 'src', and 'port' are mapped based on the 'requirements_mapping.json'.
        ```

    Note:
    - The function assumes the existence of 'requirements.json' and 'requirements_mapping.json'.
    - Any missing requirements will be stored in the 'missingRequirements' list for further investigation.
    """
    try:
        requirements_mapping = loadRequirementsMapping()
        json_file_path = get_filepath(os.path.join(outputDir,"security_intents.json"))
        with open(json_file_path, 'r') as json_file:
            data = json.load(json_file)

        yaml_data = {
            "apiVersion": "kopf.dev/v1",
            "kind": "SecurityChain",
            "metadata": {
                "name": "security-chain"
            },
            "spec": {
                "securityFunctions": []
            }
        }
 

        missingRequirements = []

        for requirement_key, requirement_info in data.items():
            if 'name' in requirement_info:
                requirement_name = translate(requirement_info['name'])
                if requirement_name == "This type of requirement is not currently supported":
                    missingRequirements.append(requirement_info['name']) 
                else:
                    if requirement_name in requirements_mapping:
                        mapping_info = requirements_mapping[requirement_name]
                    
                    # Here is where additional fields should be added to handle the default value or not.
                        security_function = {
                            "name": requirement_name,
                            "image": requirement_info.get("image", mapping_info.get("image", "")),
                            "src": requirement_info.get("src", mapping_info.get("src", "")),
                            "port": requirement_info.get("p", mapping_info.get("port", "")),
                        }
                        yaml_data["spec"]["securityFunctions"].append(security_function)
                    else:
                        print(f"Requirement not found: {requirement_name}")
            else:
                print(f"Name not found in requirement: {requirement_name}")

        with open(os.path.join(outputDir, "obj.yaml"), 'w') as yaml_file:
            yaml.dump(yaml_data, yaml_file, default_flow_style=False)
        return missingRequirements
    except Exception as e:
        return str(e)

def readDictionary(list):
    #This function reads the content of the lists
    try:
        with open("dictionary.json", 'r') as file:
            data = json.load(file)
            if list in data:
                return data[list]
            else:
                print("The list specified is not present in the dictionary")
                return
    except:
        print("An error occurred while trying to read the dictionary")

def getLists():
    #This function get all the lists present in the dictionary
    lists = []
    try:
        with open("dictionary.json", 'r') as file:
            data = json.load(file)
            if isinstance(data, dict):
                for list_name, list_data in data.items():
                    if isinstance(list_data, list):
                        lists.append(list_name)
    except:  
        print("An error occurred while trying to read the name of the lists within the dictionary")
    return lists

def translate(name):
    #Translates the name get by the requirements of the user. 
    #Search in each list if there is a match and if it is present it return the name of the list.
    #The name's list will be used as index for the requirements_mapping.json file
    try:
        normalizedName = name.lower()
        listName = getLists()
        for nameList in listName:
            list = readDictionary(nameList)
            if normalizedName in list:
                return nameList
        return "This type of requirement is not currently supported"
    except Exception as e:
        print(f"Something bad occured during translation: {str(e)}")

def loadRequirementsMapping():
    """
    Output: Returns a Python dictionary loaded from the "requirements_mapping.json" file.
    Purpose: This function reads a JSON file containing mapping information and returns it as a dictionary. 
    This mapping is used in the toYaml() function to map JSON data to the correct format in the YAML.
    """
    with open("requirements_mapping.json", 'r') as mapping_file:
        return json.load(mapping_file)

def deploy ():
    """
    Purpose: This function changes the current working directory, attempts to run a Python script named "script.py" 
    located in the parent directory, and then restores the original working directory. 
    It also prints any errors encountered during the process.
    """
    current_directory = os.getcwd()
    try:
        
        folder = os.path.dirname(os.getcwd())
        script = "script.py"
        os.chdir(folder)
        subprocess.run(["python3", script])

    except Exception as e:
        print(f"An error has occurred: {e}")
    finally:   
        os.chdir(current_directory)

