"""CLI option wrapper for argparse.

This module provides a convenient wrapper around argparse to define command-line interface
options using the :class:`Option` class. It supports automatic argument registration,
default values, and custom types, including boolean flags.
"""

import argparse

from functools import cached_property
from typing import Any, Callable


class Option:
    """Represents a CLI option.

    Provides a declarative interface to define command-line options that can be
    added to an :class:`argparse.ArgumentParser` instance via its
    :meth:`~argparse.ArgumentParser.add_argument` method.

    Args:
        *flags:
            One or more command-line flag strings for this option.
            These are passed directly to argparse's :meth:`~argparse.ArgumentParser.add_argument`.
            The first long flag (if any) is used to derive the internal name,
            which is also used as the destination (:meth:`dest`) when parsing.

            Three examples:
                .. code-block:: python

                    Option("-c", "--config-file", ...)  # Short and long form
                    Option("--verbose", ...)  # Long form only
                    Option("-v", ...)  # Short form only

        type:
            A callable that converts the command-line string to the desired Python type.
            Typically, a built-in type like ``str``, ``int``, ``float``, or ``bool``.

        default:
            The default value to use if the option is not provided. This should match
            the specified type, although no enforcement is currently done.

        required:
            We capture the required flag so we can validate it not only against command-line
            parameters but also against the provided config file.

        **kwargs:
            Additional keyword arguments passed directly to
            :meth:`~argparse.ArgumentParser.add_argument`.
    """

    def __init__(
        self,
        *flags: str,
        type: Callable[..., Any],
        default: Any = None,
        required: bool = False,
        **kwargs: Any,
    ) -> None:
        """Initializes an Option instance."""
        self.flags = flags
        self.type = type
        self.default = default
        self.required = required
        self.kwargs = kwargs

        if required and default is not None:
            raise argparse.ArgumentTypeError(
                f"You cannot set a default in a required argument: {self.dest}"
            )

    @cached_property
    def dest(self) -> str:
        """Returns the internal variable name used by argparse for this option.

        Uses the last long flag (e.g., ``--config-file``) if present, or the first
        flag as a fallback. Dashes are converted to underscores for compatibility
        with argparse's variable naming.
        """
        first_flag = next(iter(self.flags)).lstrip("-")
        last_long_flag = None

        for f in self.flags:
            if f.startswith("--"):
                last_long_flag = f.lstrip("-")

        return (last_long_flag or first_flag).replace("-", "_")
