from __future__ import annotations

import shutil
import subprocess
import sys
from pathlib import Path

import click

from pycage.constants import MSVC_FOLDER
from pycage.helpers import get_interpreter, path_verify_directory, path_verify_existence


@click.group(help="manage virtual environment with downloaded standalone images")
def venv() -> None:
    pass


@click.command(help="upgrade internal seeder packages for virtualenv")
def upgrade_seeders() -> None:
    cmd: list[str] = [
        sys.executable,
        "-m",
        "virtualenv",
        "--upgrade-embed-wheels",
    ]
    subprocess.run(cmd)


@click.command(help="create virtual environments")
@click.option("-n", "--name", default=".venv", help="how the VENV folder schould be named")
@click.option(
    "--clear", is_flag=True, default=False, help="clear VENV folder before creation"
)
def create(
    name: str,
    clear: bool,
) -> None:
    try:
        pth_intp = get_interpreter()
    except RuntimeError:
        click.echo("Base interpreter path could not be found", err=True)
        return

    pth_venv = pth_intp.parent / name
    cmd: list[str] = [
        sys.executable,
        "-m",
        "virtualenv",
        str(pth_venv),
        "-p",
        str(pth_intp),
        "--always-copy",
        "--no-setuptools",
        "--no-periodic-update",
    ]
    if clear:
        cmd.append("--clear")

    subprocess.run(cmd)


def add_pkg(
    interpreter: Path,
    package: str,
    index: str | None = None,
    extra_index: str | None = None,
    include_prerelease: bool = False,
) -> None:
    cmd: list[str] = [
        str(interpreter),
        "-m",
        "pip",
        "install",
        "-U",
        "--no-warn-script-location",
        package,
    ]
    if index is not None:
        add_opts = ["--index-url", index]
        cmd.extend(add_opts)
    if extra_index is not None:
        add_opts = ["--extra-index-url", extra_index]
        cmd.extend(add_opts)
    if include_prerelease:
        add_opts = ["--pre"]
        cmd.extend(add_opts)

    subprocess.run(cmd)


@click.command(help="install packages directly into the virtual environment")
@click.option(
    "-p",
    "--pre",
    is_flag=True,
    default=False,
    show_default=True,
    help=("install pre-release versions"),
)
@click.option(
    "-e", "--extra-index", default=None, help="extra index to lookup packages at by pip"
)
@click.option("-i", "--index", default=None, help="index to lookup packages at by pip")
@click.argument("package")
def add(
    package: str,
    index: str | None,
    extra_index: str | None,
    pre: bool,
) -> None:
    try:
        pth_intp = get_interpreter()
    except RuntimeError:
        click.echo("Base interpreter path could not be found", err=True)
        return

    add_pkg(
        interpreter=pth_intp,
        package=package,
        index=index,
        extra_index=extra_index,
        include_prerelease=pre,
    )


@click.command(help="upgrades the integrated pip installation")
def upgrade_pip() -> None:
    try:
        pth_intp = get_interpreter()
    except RuntimeError:
        click.echo("Base interpreter path could not be found", err=True)
        return

    add_pkg(
        interpreter=pth_intp,
        package="pip",
        index=None,
        extra_index=None,
    )


@click.command(help="uninstall packages directly from the virtual environment")
@click.argument("package")
def remove(
    package: str,
) -> None:
    try:
        pth_intp = get_interpreter()
    except RuntimeError:
        click.echo("Base interpreter path could not be found", err=True)
        return

    cmd: list[str] = [
        str(pth_intp),
        "-m",
        "pip",
        "uninstall",
        package,
    ]
    subprocess.run(cmd)


@click.command(
    help="add MSVC Redistributable runtime dependencies to the root path of the environment"
)
def add_msvc_redist() -> None:
    try:
        pth_intp = get_interpreter()
    except RuntimeError:
        click.echo("Base interpreter path could not be found", err=True)
        return

    target_path = pth_intp.parent
    try:
        path_verify_directory(target_path)
    except ValueError:
        click.echo(f"Target path >{target_path}< does not seem to be a directory", err=True)
        return
    try:
        path_verify_existence(target_path)
    except FileNotFoundError:
        click.echo(f"Target path >{target_path}< does not seem to exist", err=True)
        return

    dll_files = MSVC_FOLDER.glob("**/*.dll")

    click.echo("Start copying files...")
    for dll_src in dll_files:
        click.echo(f"Copy file >{dll_src.name}<")
        shutil.copy2(dll_src, target_path)

    click.echo("Copied files successfully.")


venv.add_command(create)
venv.add_command(add)
venv.add_command(upgrade_pip)
venv.add_command(remove)
venv.add_command(upgrade_seeders)
venv.add_command(add_msvc_redist)
