import os
import subprocess

from actions_logging.app_logging import logger
from github.env import exit_on_error_and_write_summary
from terragrunt.tg_common import sanitize_work_dir
from terragrunt.constants import (PLAN_FILE, PLAN_FILE_CANDIDATE,
                                  PLAN_FILE_CANDIDATE_OUTPUT, PLAN_FILE_OUTPUT,
                                  TF_PLAN_CANDIDATE_JSON, TF_PLAN_JSON)


def execute_command(command):
    """Executes a tf/tg command and checks the exit code. needs to be run inside folder with the tf/tg configuration"""
    logger.info(f"Executing: {command}")
    result = os.system(command)
    if result != 0:
        exit_on_error_and_write_summary(f"Error executing command: {command}")

def validate_tool(tool):
    if tool == 'terraform':
        logger.info("Using Terraform")
    elif tool == 'terragrunt':
        logger.info("Using Terragrunt")
    else:
        exit_on_error_and_write_summary("Invalid TOOL setting. TOOL must be either 'terraform' or 'terragrunt'.")

# this is a preparation for possible future use of run-all command
def get_cmd_prefix(tool):
    cmd_prefix = "terraform"
    if tool == 'terragrunt':
        cmd_prefix = "terragrunt"
    return cmd_prefix

def get_command(cmd, cmd_prefix, args=''):
    """
    Lazily evaluates Terraform or Terragrunt commands.

    This function constructs the appropriate command based on the provided command name,
    command prefix (either 'terraform' or 'terragrunt'), and optional arguments.
    The function needs to be run inside a folder with Terraform or Terragrunt configuration.

    Args:
        cmd (str): The command to evaluate (e.g., 'validate', 'init', 'plan', 'apply', etc.).
        cmd_prefix (str): The command prefix ('terraform' or 'terragrunt').
        args (str, optional): Additional arguments for the command. Defaults to ''.

    Returns:
        str: The constructed command string.

    Raises:
        SystemExit: If an error occurs while evaluating the command.
    """
    try:
        args = args or ''
        commands = {
            'validate': lambda: f"{cmd_prefix} validate",
            'init': lambda: f"{cmd_prefix} init {args}",
            'plan': lambda: f"{cmd_prefix} plan -out={os.path.join(os.getcwd(), PLAN_FILE)} {args}",
            'apply': lambda: f"{cmd_prefix} apply -auto-approve {os.path.join(os.getcwd(), PLAN_FILE)} {args}",
            'plan-destroy': lambda: f"{cmd_prefix} plan -destroy -out={os.path.join(os.getcwd(), PLAN_FILE)} {args}",
            'destroy': lambda: f"{cmd_prefix} destroy -auto-approve {args}",
            'show': lambda: f"{cmd_prefix} show {args} {os.path.join(os.getcwd(), PLAN_FILE)}",
            'show-candidate': lambda: f"{cmd_prefix} show {args} {os.path.join(os.getcwd(), PLAN_FILE_CANDIDATE)}",
            'show-and-save': lambda: f"{cmd_prefix} show {args} {os.path.join(os.getcwd(), PLAN_FILE)} > {PLAN_FILE_OUTPUT}",
            'show-and-save-candidate': lambda: f"{cmd_prefix} show {args} {os.path.join(os.getcwd(), PLAN_FILE_CANDIDATE)} > {PLAN_FILE_CANDIDATE_OUTPUT}",
            'show-json': lambda: f"{cmd_prefix} show -json {args} {os.path.join(os.getcwd(), PLAN_FILE)} > {TF_PLAN_JSON}",
            'show-json-candidate': lambda: f"{cmd_prefix} show -json {args} {os.path.join(os.getcwd(), PLAN_FILE_CANDIDATE)} > {TF_PLAN_CANDIDATE_JSON}",
        }
        return commands[cmd]()
    except Exception as e:
        exit_on_error_and_write_summary(f"Couldn't evaluate cli command. Error: {e}")

def run_iac_command(work_dir, tool, command, args=''):
    cmd_prefix = get_cmd_prefix(tool)
    cwd_orig = os.getcwd()
    os.chdir(work_dir)
    iac_command = get_command(command, cmd_prefix, args)
    execute_command(iac_command)
    os.chdir(cwd_orig)


def diff_files(work_dir, first_file, second_file):
    try:
        first_plan = os.path.join(work_dir, first_file)
        second_plan = os.path.join(work_dir, second_file)
        diff_exists = subprocess.run(['git', 'diff', '--no-index', first_plan, second_plan], text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        if diff_exists.returncode != 0 and not diff_exists.stderr:
            return diff_exists.stdout
        elif diff_exists.stderr:
            raise RuntimeError(diff_exists.stderr)
        else:
            return None
    except Exception as e:
        exit_on_error_and_write_summary(f"An error occurred: {e}")

def main():
    work_dir = sanitize_work_dir(os.getenv('WORK_DIR'))
    tool = os.getenv('TOOL')
    validate_tool(tool)

    command = os.getenv('COMMAND')
    args = os.getenv('ARGS')

    run_iac_command(work_dir, tool, command, args)

if __name__ == "__main__":
    main()
