import sys
from pathlib import Path
from typing import Optional

import typer
from py_app_dev.core.exceptions import UserNotificationException
from py_app_dev.core.logging import logger, setup_logger, time_it

from yanga import __version__

from .commands.run import RunCommand, RunCommandConfig
from .gui import YangaGui
from .kickstart.create import KickstartProject
from .yide import IDEProjectGenerator
from .yview import KConfigView

package_name = "yanga"

app = typer.Typer(name=package_name, help="YANGA command line interface.", no_args_is_help=True, add_completion=False)


def make_absolute_path(path_value: str | Path) -> Path:
    return Path(path_value).absolute()


project_dir_option = typer.Option(Path.cwd(), callback=make_absolute_path, help="The project directory")


@app.callback(invoke_without_command=True)
def version(
    version: bool = typer.Option(None, "--version", "-v", is_eager=True, help="Show version and exit."),
) -> None:
    if version:
        typer.echo(f"{package_name} {__version__}")
        raise typer.Exit()


@app.command(help="Initialize a new YANGA project in the specified directory.")
@time_it("init")
def init(
    project_dir: Path = project_dir_option,
    force: bool = typer.Option(False, help="Force the initialization of the project even if the directory is not empty."),
    sources: bool = typer.Option(True, help="Copy the example SPL sources."),
) -> None:
    KickstartProject(project_dir, force, sources).run()


@app.command(help="Run the build pipeline for a specific variant and component.")
@time_it("run")
def run(
    project_dir: Path = project_dir_option,
    platform: Optional[str] = typer.Option(
        None,
        help="Platform for which to build (see the available platforms in the configuration).",
    ),
    variant: Optional[str] = typer.Option(
        None,
        help="SPL variant name. If none is provided, it will prompt to select one.",
    ),
    component: Optional[str] = typer.Option(
        None,
        help="Restrict the scope to one specific component.",
    ),
    target: Optional[str] = typer.Option(
        None,
        help="Define a specific target to execute.",
    ),
    build_type: Optional[str] = typer.Option(
        None,
        help="Build type to use (e.g., 'Debug', 'Release').",
    ),
    step: Optional[str] = typer.Option(
        None,
        help="Name of the step to run (as written in the pipeline config).",
    ),
    single: bool = typer.Option(
        False,
        help="If provided, only the provided step will run, without running all previous steps in the pipeline.",
    ),
    print: bool = typer.Option(
        False,
        help="Print the pipeline steps.",
    ),
    force_run: bool = typer.Option(
        False,
        help="Force the execution of a step even if it is not dirty.",
    ),
    not_interactive: bool = typer.Option(
        False,
        help="Run in non-interactive mode (no prompts).",
    ),
) -> None:
    RunCommand().do_run(
        RunCommandConfig(
            project_dir,
            platform,
            variant,
            component,
            target,
            build_type,
            step,
            single,
            print,
            force_run,
            not_interactive,
        )
    )


@app.command(help="Launch the YANGA GUI to build variants and components.")
@time_it("gui")
def gui(
    project_dir: Path = project_dir_option,
) -> None:
    YangaGui(project_dir).run()


@app.command(help="View the variants feature configurations.")
@time_it("view")
def view(
    project_dir: Path = project_dir_option,
) -> None:
    KConfigView(project_dir).run()


@app.command(help="Generate the VS Code project files.")
@time_it("ide")
def ide(
    project_dir: Path = project_dir_option,
) -> None:
    IDEProjectGenerator(project_dir).run()


def main() -> int:
    try:
        setup_logger()
        app()
        return 0
    except UserNotificationException as e:
        logger.error(f"{e}")
        return 1


if __name__ == "__main__":
    sys.exit(main())
