# Copyright (c) 2017-2026 Juancarlo Añez (apalala@gmail.com)
# SPDX-License-Identifier: BSD-4-Clause
"""CLI for TatSu, mirroring ogopego's three-subcommand structure."""

from __future__ import annotations

import argparse
import signal
import sys
from argparse import ArgumentParser

from .. import __toolname__, __version__, g2e
from ..exceptions import ParseException
from ..tool import bench, ideps
from ..util.checkpygments import is_pygments_available
from .boot_cmd import add_boot_cmd, boot_cmd
from .cfg import CLIConfig, CLIError
from .global_opt import add_global_options
from .grammar_cmd import add_grammar_cmd, grammar_cmd
from .out import output_results
from .run_cmd import run_cmd
from .run_opt import add_run_cmd


TITLE = "竜TatSu"
VERSION = f"{TITLE} v{__version__}"
DESCRIPTION = (
    f'{TITLE} takes a grammar in extended EBNF'
    ' as input, and outputs a memoizing'
    ' PEG/Packrat parser in Python.'
)


def create_argument_parser() -> ArgumentParser:

    # Handle --version before argparse to match ogopego's pre-dispatch check
    parser = argparse.ArgumentParser(
        prog="tatsu",
        description=DESCRIPTION,
    )

    sub = parser.add_subparsers(
        dest="command",
        description="Main execution mode",
        required=False,
        help="Available subcommands",
    )

    parser.add_argument(
        "-V",
        "--version",
        action="version",
        version=f"{__toolname__} {__version__}",
        help="Print version information and exit",
    )
    add_global_options(parser)
    # _help_cmd = add_help_cmd(subparsers)
    _boot_cmd = add_boot_cmd(sub)
    _grammar_cmd = add_grammar_cmd(sub)
    _run_cmd = add_run_cmd(sub)
    _g2e_cmd = g2e.add_g2e_cmd(sub)
    _bench_cmd = bench.add_bench_cmd(sub)
    _ideps_cmd = ideps.add_ideps_cmd(sub)
    return parser


def run_cling_cli(parser: argparse.ArgumentParser) -> CLIConfig:
    """Parse command-line arguments and return a CLIConfig.

    Matches ogopego's subcommand structure (run / boot / grammar).
    """
    cfg = CLIConfig()
    namespace = parser.parse_args(namespace=cfg)

    for name, value in vars(namespace).items():
        if name == "name":
            continue
        if not hasattr(cfg, name):
            raise RuntimeError(f"Unknown option: {name}")
        setattr(cfg, name, value)
    return cfg


def cling_main() -> int:  # noqa: PLR0911
    """Entry point for the cling CLI (not wired to console_scripts yet)."""

    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
    parser = create_argument_parser()
    try:
        cfg = run_cling_cli(parser)

        if cfg.style == "list":
            if is_pygments_available():
                from pygments.styles import get_all_styles

                for style in sorted(get_all_styles()):
                    print(style)
            else:
                print("pygments not installed", file=sys.stderr)
                print("install with: pip install tatsu[cling]", file=sys.stderr)
            return 0
        match cfg.command:
            case "boot":
                results = boot_cmd(cfg)
            case "grammar":
                results = grammar_cmd(cfg)
            case "run":
                results = run_cmd(cfg)
            case "bench":
                return bench.bench_cmd(parser)
            case "g2e":
                return g2e.g2e_cmd(parser)
            case "ideps":
                return ideps.ideps_cmd(parser)
            case _:
                parser.print_usage()
                return 1
        output_results(cfg, results)
        return 0

    except CLIError as e:
        print(e, file=sys.stderr)
        return 1
    except ParseException as e:
        print(e, file=sys.stderr)
        return 1
    except BrokenPipeError:
        return signal.SIGPIPE + 0o200
    except KeyboardInterrupt:
        return signal.SIGINT + 0o200


def add_help_cmd(subparsers):
    help_parser = subparsers.add_parser(
        "help",
        help="Provide command help",
        add_help=False,
    )
    return help_parser
