import re
from pathlib import Path
from typing import Any, Iterable, Union

import click
import yaml
from jinja2 import Environment, FileSystemLoader
from kedro.framework.cli.utils import CONTEXT_SETTINGS
from kedro.framework.project import settings
from kedro.framework.session import KedroSession
from kedro.framework.startup import bootstrap_project
from kedro.utils import find_kedro_project, is_kedro_project
from kedro.framework.cli.project import TAG_ARG_HELP

GITOPS_TEMPLATES_DIR_PATH = Path(__file__).parent / "templates"


def render_jinja_template(
    src: Union[str, Path],
    trim_blocks: bool = False,
    lstrip_blocks: bool = False,
    keep_trailing_newline: bool = True,
    **kwargs
) -> str:
    """Render a Jinja2 template file with the provided values.

    Args:
        src: The path to the template file to render
        trim_blocks: If True, remove the first newline after a block
        lstrip_blocks: If True, strip leading spaces and tabs from the start of a line
        keep_trailing_newline: If True, preserve trailing newlines
        **kwargs: Variables to pass to the template for rendering

    Returns:
        A string containing the rendered template with replaced tags.
    """
    src = Path(src)
    template_loader = FileSystemLoader(searchpath=src.parent.as_posix())
    template_env = Environment(
        loader=template_loader,
        trim_blocks=trim_blocks,
        lstrip_blocks=lstrip_blocks,
        keep_trailing_newline=keep_trailing_newline,
    )
    template = template_env.get_template(src.name)
    return template.render(**kwargs)


def write_jinja_template(
    src: Union[str, Path],
    dst: Union[str, Path],
    trim_blocks: bool = False,
    lstrip_blocks: bool = False,
    keep_trailing_newline: bool = True,
    **kwargs
) -> None:
    """Write a rendered Jinja2 template to a file.

    Args:
        src: Path to the template file to render
        dst: Path where the rendered template should be saved
        trim_blocks: If True, remove the first newline after a block
        lstrip_blocks: If True, strip leading spaces and tabs from the start of a line
        keep_trailing_newline: If True, preserve trailing newlines
        **kwargs: Variables to pass to the template for rendering
    """
    dst = Path(dst)
    parsed_template = render_jinja_template(
        src,
        trim_blocks=trim_blocks,
        lstrip_blocks=lstrip_blocks,
        keep_trailing_newline=keep_trailing_newline,
        **kwargs
    )
    with open(dst, "w") as file_handler:
        file_handler.write(parsed_template)


def copy_file(src: Union[str, Path], dst: Union[str, Path]) -> None:
    """Copy a file from source to destination.

    Args:
        src: Path to the source file to copy
        dst: Path where the file should be copied to
    """
    src = Path(src)
    dst = Path(dst)
    
    with open(src, "r") as src_file:
        content = src_file.read()
    
    with open(dst, "w") as dst_file:
        dst_file.write(content)


@click.group(context_settings=CONTEXT_SETTINGS)
def cli():
    pass

class KedroClickGroup(click.Group):
    def reset_commands(self):
        self.commands = {}

        # add commands on the fly based on conditions
        if is_kedro_project(find_kedro_project(Path.cwd())):
            self.add_command(init)

    def list_commands(self, ctx):
        self.reset_commands()
        commands_list = sorted(self.commands)
        return commands_list

    def get_command(self, ctx, cmd_name):
        self.reset_commands()
        return self.commands.get(cmd_name)

@click.group(name="gitops")
def commands():
    pass

@commands.command(name="gitops", cls=KedroClickGroup)
def gitops_commands():
    """Use gitops-specific commands inside kedro project."""
    pass  # pragma: no cover

@gitops_commands.command()
@click.option(
    "--env",
    "-e",
    default="base",
    help="The name of the kedro environment where the 'gitops.yml' should be created. Default to 'base'",
)
@click.option(
    "--force",
    "-f",
    is_flag=True,
    default=False,
    help="Update the template without any checks.",
)
@click.option(
    "--silent",
    "-s",
    is_flag=True,
    default=False,
    help="Should message be logged when files are modified?",
)
def init(env: str, force: bool, silent: bool):
    """Updates the template of a kedro project.
    Running this command is mandatory to use gitops-kedro.
    This adds "conf/base/gitops.yml": This is a configuration file
    used for run parametrization when calling "kedro run" command.
    """

    # get constants
    gitops_yml = "gitops.yml"
    project_path = find_kedro_project(Path.cwd()) or Path.cwd()
    project_metadata = bootstrap_project(project_path)
    gitops_yml_path = project_path / settings.CONF_SOURCE / env / gitops_yml

    if gitops_yml_path.is_file() and not force:
        click.secho(
            click.style(
                f"A 'gitops.yml' already exists at '{gitops_yml_path}' You can use the ``--force`` option to override it.",
                fg="red",
            )
        )
    else:
        try:
            write_jinja_template(
                src=GITOPS_TEMPLATES_DIR_PATH / gitops_yml,
                dst=gitops_yml_path,
                python_package=project_metadata.package_name,
            )
            if not silent:
                click.secho(
                    click.style(
                        f"'{settings.CONF_SOURCE}/{env}/{gitops_yml}' successfully updated.",
                        fg="green",
                    )
                )
        except FileNotFoundError:
            click.secho(
                click.style(
                    f"No env '{env}' found. Please check this folder exists inside '{settings.CONF_SOURCE}' folder.",
                    fg="red",
                )
            )