"""Base command dataclass for composable CLI trees."""

from __future__ import annotations

from argparse import ArgumentParser
from dataclasses import dataclass, fields
from typing import Any, ClassVar, Dict, List, Optional, Type


@dataclass
class CLICommand:
    """Base class for CLI commands.

    Subclasses define their identity (name, help, description) as
    dataclass fields.  These are passed as kwargs to
    ``subparsers.add_parser()``.

    Override ``add_arguments`` to register flags and positionals.
    Override ``execute`` to implement the command's logic.

    Nest subcommands by setting ``_subcommands`` as a class variable.
    """

    name: str = ""
    help: str = ""
    description: str = ""

    _subcommands: ClassVar[List[Type[Command]]] = []

    def add_arguments(self, parser: ArgumentParser) -> None:
        """Add arguments to the parser.  Override in subclasses."""

    def execute(self, args: Any) -> int:
        """Run the command.  Override in subclasses.

        Returns an exit code (0 = success).
        """
        return 0

    def parser_kwargs(self) -> Dict[str, Any]:
        """Return the dataclass fields as kwargs for add_parser.

        Excludes ``name`` (used as the positional parser name) and
        any empty-string fields so argparse defaults apply.
        """
        skip = {"name"}
        kwargs = {}
        for f in fields(self):
            if f.name in skip or f.name.startswith("_"):
                continue
            val = getattr(self, f.name)
            if val != "":
                kwargs[f.name] = val
        return kwargs
