"""The main entry point for the slices cli."""

import os
import sys

from slices_cli.completion import install_completion, print_completion_script
from slices_cli.options import OPTIONS_WITH_ARGS, OPTIONS_WITHOUT_ARGS

from . import err_console
from .cache import clear_cache
from .child_exec import exec_subcommand
from .help import print_clear_cache_help, print_completion_help, print_help
from .print_version import print_version
from .upgrade_check import do_upgrade_check


def _next_options(argv: list[str]) -> list[str]:
    res = []
    for arg in argv:
        if arg.startswith("-"):
            res.append(arg)
        else:
            break
    return res


def _has_command(argv: list[str]) -> bool:
    return any(not arg.startswith("-") for arg in argv)


def handle_obsolete_completion():
    """Handle the case where the user is using the old version of command line tab completions."""

    if os.environ.get("_SLICES_COMPLETE", "").startswith("complete_"):
        err_console.print(
            "[red bold] :x: You are using the old version of command line tab completions!", highlight=False
        )
        err_console.print("[red bold] Upgrade with: slices completion install")
        sys.exit(1)


def process_args(argv: list[str]) -> tuple[set[str], list[str], list[str]]:
    """Split the arguments into flags, options with args, and other arguments."""
    argv = list(argv)
    processing_flags = True

    flags = set()
    options_with_arg = []
    other = []

    while len(argv) > 0:
        arg = argv.pop(0)

        if processing_flags:
            if arg in OPTIONS_WITHOUT_ARGS:
                flags.add(arg)
                continue
            if arg in OPTIONS_WITH_ARGS:
                options_with_arg.append(arg)
                options_with_arg.append(argv.pop(0))
                continue

        # unrecognized option, or command: stop processing flags and options
        processing_flags = False
        other.append(arg)
    return flags, options_with_arg, other


def _handle_clear_cache(other: list[str]):
    """Handle the clear-cache command."""
    next_options = _next_options(other)
    non_help_options = [o for o in next_options if o not in ["--help", "-h"]]
    if len(non_help_options) < len(next_options):
        print_clear_cache_help()
        sys.exit(0)

    if _has_command(next_options) or non_help_options:
        err_console.print("[red bold] :x: Unrecognized argument to clear-cache", highlight=False)
        print_clear_cache_help()
        sys.exit(1)

    clear_cache()
    sys.exit(0)


def _handle_completion_command(other: list[str]):
    """Handle the completion command."""
    next_commands = [arg for arg in other if not arg.startswith("-")]
    next_command = next_commands[0] if next_commands else None
    help_options = [o for o in other if o in ["--help", "-h"]]
    non_help_options = [o for o in other if o.startswith("-") and o not in ["--help", "-h"]]

    # wherever there is any --help after completion, show completion help
    if help_options:
        print_completion_help()
        sys.exit(0)

    if non_help_options:
        err_console.print(f"[red bold] :x: Unrecognized option: {non_help_options[0]}", highlight=False)
        print_completion_help()
        sys.exit(1)

    if not next_command:
        err_console.print("[red bold] :x: 'completion' requires a command ('install' or 'show')", highlight=False)
        print_completion_help()
        sys.exit(1)

    if len(next_commands) > 1:
        err_console.print(f"[red bold] :x: Unrecognized argument: {next_commands[1]}", highlight=False)
        print_completion_help()
        sys.exit(1)

    if next_command == "install":
        install_completion()
        sys.exit(0)

    if next_command == "show":
        print_completion_script()
        sys.exit(0)

    if next_command:
        err_console.print(f"[red bold] :x: Unrecognized argument: {next_command}", highlight=False)
        print_completion_help()
        sys.exit(1)


def main():
    """Run the slices cli."""

    handle_obsolete_completion()

    argv = list(sys.argv)

    argv.pop(0)  # pop slices executable

    flags, options_with_arg, other = process_args(argv)

    if "-v" in flags or "-vv" in flags or "-vvv" in flags:
        err_console.print("[red bold]'slices -v' is not supported. Try -v on a subcommand instead.\n")
        print_help()
        sys.exit(1)

    if "--help" in flags or "-h" in flags:
        print_help()
        sys.exit(0)

    if "--version" in flags:
        print_version()
        sys.exit(0)

    # All options with args (options_with_arg) are ignored by this CLI

    while len(other) > 0:
        arg = other.pop(0)
        if arg.startswith("-"):
            # The main slices cli only allows a few specific options.
            # Any other options must be passed to the subcommand.
            err_console.print(f"[red bold] :x: Unrecognized option: {arg}", highlight=False)
            print_help()
            sys.exit(1)

        if arg == "clear-cache":
            _handle_clear_cache(other)

        if arg == "completion":
            _handle_completion_command(other)

        if "--no-upgrade-check" not in flags:
            do_upgrade_check()

        exec_subcommand(arg)

    err_console.print("[red bold] :x: No subcommand specified.")
    print_help()
    sys.exit(1)


if __name__ == "__main__":
    main()
