from pathlib import Path
import yaml
import click

from soopervisor import __version__
from soopervisor import config
from soopervisor import exporter
from soopervisor.enum import Backend, Mode
from soopervisor.telemetry import telemetry


@click.group()
@click.version_option(version=__version__)
def cli():
    """
    Soopervisor exports Ploomber projects.

    Example (export to Argo Workflows for training):

    $ soopervisor add training --backend argo-workflows

    $ soopervisor export training

    """
    pass


@cli.command()
@click.argument("env_name")
@click.option("--backend", "-b", type=click.Choice(Backend.get_values()), required=True)
@click.option(
    "--preset", "-p", help="Customizes settings (backend-specific)", default=None
)
def add(env_name, backend, preset):
    """
    Add a new target platform. Creates a 'soopervisor.yaml' file if needed

    Example: soopervisor add cluster-training -b argo-workflows
    """
    backend = Backend(backend)

    try:
        if Path("soopervisor.yaml").exists():
            cfg = yaml.safe_load(Path("soopervisor.yaml").read_text())
            if env_name in cfg:
                raise click.ClickException(
                    f"A {env_name!r} section in the "
                    "soopervisor.yaml configuration file "
                    "already exists. Choose another name."
                )
        if Path(env_name).exists():
            raise click.ClickException(
                f"{env_name!r} already exists. Select a different name."
            )
    except Exception as e:
        telemetry.log_api(
            "soopervisor_add_error",
            metadata={"type": backend.value, "env_name": env_name, "error": str(e)},
        )
        raise

    Exporter = exporter.for_backend(backend)
    Exporter.new("soopervisor.yaml", env_name=env_name, preset=preset).add()

    telemetry.log_api(
        "soopervisor_add_success",
        metadata={"type": backend.value, "env_name": env_name},
    )

    click.echo(
        "Environment added, to export it:\n"
        f"\t $ soopervisor export {env_name}\n"
        "To force execution of all tasks:\n"
        f"\t $ soopervisor export {env_name} "
        "--mode force\n"
    )


@cli.command()
@click.argument("env_name")
@click.option("--until-build", "-u", is_flag=True, help="Only build docker image")
@click.option("--skip-tests", "-s", is_flag=True, help="Skip docker image tests")
@click.option("--skip-docker", "-S", is_flag=True, help="Skip docker build")
@click.option(
    "--mode", "-m", type=click.Choice(Mode.get_values()), default=Mode.incremental.value
)
@click.option(
    "--ignore-git",
    "-i",
    is_flag=True,
    help="Ignore git tracked files (include everything)",
)
@click.option("--lazy", "-l", is_flag=True, help="Lazily load pipeline")
@click.option(
    "--task", "-t", type=str, help="Execute a single task with the given name"
)
def export(
    env_name, until_build, mode, skip_tests, skip_docker, ignore_git, lazy, task
):
    """
    Export a target platform for execution/deployment
    """
    input_args = {
        "env_name": env_name,
        "until_build": until_build,
        "mode": mode,
        "skip_tests": skip_tests,
        "skip_docker": skip_docker,
        "ignore_git": ignore_git,
        "task": task,
    }

    backend = Backend(config.get_backend(env_name))

    telemetry.log_api(
        "soopervisor_export_started",
        metadata={"type": backend.value, "input_args": input_args},
    )

    until = None

    if until_build:
        until = "build"

    # TODO: ignore mode if using aws lambda, raised exception if value
    # is not the default
    if backend == Backend.aws_lambda:
        mode = None

    Exporter = exporter.for_backend(backend)

    try:
        Exporter.load("soopervisor.yaml", env_name=env_name, lazy_import=lazy).export(
            mode=mode,
            until=until,
            skip_tests=skip_tests,
            skip_docker=skip_docker,
            ignore_git=ignore_git,
            lazy_import=lazy,
            task_name=task,
        )

    except Exception as e:
        telemetry.log_api(
            "soopervisor_export_error",
            metadata={"type": backend.value, "input_args": input_args, "error": str(e)},
        )
        raise

    telemetry.log_api(
        "soopervisor_export_success",
        metadata={"type": backend.value, "input_args": input_args},
    )


if __name__ == "__main__":
    cli()
