from pathlib import Path
import sys

import typer

from uv_secure import __version__
from uv_secure.dependency_checker import check_lock_files, RunStatus


DEFAULT_HTTPX_CACHE_TTL_SECONDS = 24.0 * 60.0 * 60.0


app = typer.Typer()


def _version_callback(value: bool) -> None:
    if value:
        typer.echo(f"uv-secure {__version__}")
        raise typer.Exit()


_file_path_args = typer.Argument(
    None,
    help=(
        "Paths to the uv.lock or uv generated requirements.txt files or a single "
        "project root level directory (defaults to working directory if not set)"
    ),
)


_aliases_option = typer.Option(
    None,
    "--aliases",
    help="Flag whether to include vulnerability aliases in the vulnerabilities table",
)


_desc_option = typer.Option(
    None,
    "--desc",
    help=(
        "Flag whether to include vulnerability detailed description in the "
        "vulnerabilities table"
    ),
)

_cache_path_option = typer.Option(
    Path.home() / ".cache/uv-secure",
    "--cache-path",
    help="Path to the cache directory for vulnerability http requests",
    show_default="~/.cache/uv-secure",
)

_cache_ttl_seconds_option = typer.Option(
    DEFAULT_HTTPX_CACHE_TTL_SECONDS,
    "--cache-ttl-seconds",
    help="Time to live in seconds for the vulnerability http requests cache",
)

_disable_cache_option = typer.Option(
    False,
    "--disable-cache",
    help="Flag whether to disable caching for vulnerability http requests",
)

_forbid_yanked_option = typer.Option(
    None,
    "--forbid-yanked",
    help="Flag whether disallow yanked package versions from being dependencies",
)

_check_direct_dependency_vulnerabilities_only_option = typer.Option(
    None,
    "--check-direct-dependency-vulnerabilities-only",
    help="Flag whether to only test only direct dependencies for vulnerabilities",
)

_check_direct_dependency_maintenance_issues_only_option = typer.Option(
    None,
    "--check-direct-dependency-maintenance-issues-only",
    help="Flag whether to only test only direct dependencies for maintenance issues",
)

_max_package_age_option = typer.Option(
    None, "--max-age-days", help="Maximum age threshold for packages in days"
)

_ignore_vulns_option = typer.Option(
    None,
    "--ignore-vulns",
    help="Comma-separated list of vulnerability IDs to ignore, e.g. VULN-123,VULN-456",
)

_config_option = typer.Option(
    None,
    "--config",
    help=(
        "Optional path to a configuration file (uv-secure.toml, .uv-secure.toml, or "
        "pyproject.toml)"
    ),
)

_version_option = typer.Option(
    None,
    "--version",
    callback=_version_callback,
    is_eager=True,
    help="Show the application's version",
)


_ignore_pkg_options = typer.Option(
    None,
    "--ignore-pkgs",
    metavar="PKG:SPEC1|SPEC2|…",
    help=(
        "Dependency with optional version specifiers. "
        "Syntax: name:spec1|spec2|…  "
        "e.g. foo:>=1.0,<1.5|==4.5.*"
    ),
)


@app.command()
def main(
    file_paths: list[Path] | None = _file_path_args,
    aliases: bool | None = _aliases_option,
    desc: bool | None = _desc_option,
    cache_path: Path = _cache_path_option,
    cache_ttl_seconds: float = _cache_ttl_seconds_option,
    disable_cache: bool = _disable_cache_option,
    forbid_yanked: bool | None = _forbid_yanked_option,
    max_package_age: int | None = _max_package_age_option,
    ignore_vulns: str | None = _ignore_vulns_option,
    ignore_pkgs: list[str] | None = _ignore_pkg_options,
    check_direct_dependency_vulnerabilities_only: bool
    | None = _check_direct_dependency_vulnerabilities_only_option,
    check_direct_dependency_maintenance_issues_only: bool
    | None = _check_direct_dependency_maintenance_issues_only_option,
    config_path: Path | None = _config_option,
    version: bool = _version_option,
) -> None:
    """Parse uv.lock files, check vulnerabilities, and display summary."""

    # Use uvloop or winloop if present
    try:
        if sys.platform in {"win32", "cygwin", "cli"}:
            from winloop import run
        else:
            from uvloop import run
    except ImportError:
        from asyncio import run

    run_status = run(
        check_lock_files(
            file_paths,
            aliases,
            desc,
            cache_path,
            cache_ttl_seconds,
            disable_cache,
            forbid_yanked,
            max_package_age,
            ignore_vulns,
            ignore_pkgs,
            check_direct_dependency_vulnerabilities_only,
            check_direct_dependency_maintenance_issues_only,
            config_path,
        )
    )
    if run_status == RunStatus.MAINTENANCE_ISSUES_FOUND:
        raise typer.Exit(code=1)
    if run_status == RunStatus.VULNERABILITIES_FOUND:
        raise typer.Exit(code=2)
    if run_status == RunStatus.RUNTIME_ERROR:
        raise typer.Exit(code=3)


if __name__ == "__main__":
    app()  # pragma: no cover
