import os
import yaml
import logging
import time
import subprocess
from kubernetes import client, config

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Function to replace placeholders with values
def replace_placeholders(data, placeholders):
    if 'spec' in data:
        if 'destination' in data['spec'] and 'namespace' in data['spec']['destination']:
            data['spec']['destination']['namespace'] = placeholders['spec']['destination']['namespace']
        if 'project' in data['spec']:
            data['spec']['project'] = placeholders['spec']['project']
        if 'source' in data['spec']:
            if 'path' in data['spec']['source']:
                parts = data['spec']['source']['path'].split('/')
                parts[0] = placeholders['spec']['source']['parentPath']
                data['spec']['source']['path'] = '/'.join(parts)
            if 'repoURL' in data['spec']['source']:
                data['spec']['source']['repoURL'] = placeholders['spec']['source']['repoURL']
    return data

# Function to check the status of a pod
def check_pod_status(namespace, pod_name):
    config.load_kube_config()
    v1 = client.CoreV1Api()

    try:
        pod = v1.read_namespaced_pod(name=pod_name, namespace=namespace)
        
        if pod.status.phase == "Running":
            logging.info(f"Pod {pod_name} is running.")
            ready_containers = 0
            total_containers = len(pod.spec.containers)
            
            for container_status in pod.status.container_statuses:
                if container_status.ready:
                    ready_containers += 1
            
            if ready_containers == total_containers:
                logging.info(f"All containers in pod {pod_name} are ready ({ready_containers}/{total_containers}).")
                return True
            else:
                logging.info(f"Not all containers in pod {pod_name} are ready ({ready_containers}/{total_containers}).")
                return False
        else:
            logging.info(f"Pod {pod_name} is not running. Current status: {pod.status.phase}")
            return False
    except client.exceptions.ApiException as e:
        logging.error(f"Exception when calling CoreV1Api->read_namespaced_pod: {e}")
        return False

# Function to apply YAML file and wait for pod status
def apply_and_wait(file_path, placeholders):
    with open(file_path, 'r') as f:
        data = yaml.safe_load(f)

    data = replace_placeholders(data, placeholders)

    # Write the modified YAML to a temporary file
    temp_file = "temp_application.yaml"
    with open(temp_file, 'w') as f:
        yaml.dump(data, f)

    # Apply the YAML file
    logging.info(f"Applying YAML file: {file_path}")
    subprocess.run(["kubectl", "apply", "-f", temp_file], check=True)

    # Extract the pod name and namespace from the YAML
    pod_name = data['metadata']['name']
    namespace = data['spec']['destination']['namespace']

    # Wait for the pod to be ready
    logging.info(f"Waiting for pod {pod_name} in namespace {namespace} to be ready...")
    while not check_pod_status(namespace, pod_name):
        time.sleep(10)  # Wait for 10 seconds before checking again

    logging.info(f"Pod {pod_name} is ready. Proceeding to the next file.")

    # Save the modified YAML to the specified directory
    save_dir = os.path.expanduser('~/Configurations/ApplicationControl/')
    os.makedirs(save_dir, exist_ok=True)
    save_path = os.path.join(save_dir, os.path.basename(file_path))
    with open(save_path, 'w') as f:
        yaml.dump(data, f)

    # Clean up the temporary file
    os.remove(temp_file)

# Load the placeholders from placeholders.yaml
with open('placeholders.yaml', 'r') as f:
    placeholders = yaml.safe_load(f)

# Iterate through files inside the 01, 02, 03, 04 dirs and apply the application control YAMLs in the cluster
# The script waits until the pod is ready in each iteration
for dir in sorted(os.listdir(".")):
    if not os.path.isdir(dir):
        continue
    if not dir.startswith("0"):
        continue
    if dir.startswith("05"):
        continue
    
    for file in sorted(os.listdir(dir)):
        if not file.endswith(".yaml") and not file.endswith(".yml"):
            continue

        file_path = os.path.join(dir, file)
        apply_and_wait(file_path, placeholders)

# Iterate through files inside the 05 dir and apply the application control YAMLs in the cluster
# The script does not need to wait until the pod is ready in each iteration
for file in sorted(os.listdir("05")):
    if not file.endswith(".yaml") and not file.endswith(".yml"):
        continue

    file_path = os.path.join("05", file)
    with open(file_path, 'r') as f:
        data = yaml.safe_load(f)

    data = replace_placeholders(data, placeholders)

    # Write the modified YAML to a temporary file
    temp_file = "temp_application.yaml"
    with open(temp_file, 'w') as f:
        yaml.dump(data, f)

    # Apply the YAML file
    logging.info(f"Applying YAML file: {file_path}")
    subprocess.run(["kubectl", "apply", "-f", temp_file], check=True)

    # Save the modified YAML to the specified directory
    save_dir = os.path.expanduser('~/Configurations/ApplicationControl/')
    os.makedirs(save_dir, exist_ok=True)
    save_path = os.path.join(save_dir, os.path.basename(file_path))
    with open(save_path, 'w') as f:
        yaml.dump(data, f)

    # Clean up the temporary file
    os.remove(temp_file)