"""
Configuration for trspecfit function libraries.

This module defines which functions are available for use as spectral components,
time dynamics, profile functions, and convolution kernels. It provides utilities for:
- Identifying function types (backgrounds, convolutions, regular components)
- Managing component naming/numbering rules
- Discovering available functions dynamically from function libraries

The configuration here determines how the YAML parser handles component definitions
and how the mcp module constructs models from user input.
"""

import inspect

from trspecfit.functions import energy as fcts_energy
from trspecfit.functions import profile as fcts_profile
from trspecfit.functions import time as fcts_time


#
def all_functions() -> tuple[str, ...]:
    """
    Dynamically discover all available function names from the functions modules.
    Returns a set of all function names that can be used as components.
    """

    function_names = set()

    # Get all function names from each module
    for module in [fcts_energy, fcts_time, fcts_profile]:
        for name in dir(module):
            # Only include callable functions (not constants or classes)
            if callable(getattr(module, name)) and not name.startswith("_"):
                function_names.add(name)

    return tuple(function_names)


#
def numbering_exceptions() -> tuple[str, ...]:
    """
    Get function names that should not receive automatic numbering.

    These functions have special behavior in model construction:
    - Background functions: Only one instance makes sense per model
    - Convolution functions: Applied globally, not per-component

    Returns
    -------
    tuple of str
        Function names that should not be numbered
    """

    # none is a placeholder function to define an empty mcp.Dynamics subcycle
    # theoretically, someone could want multiple empty subcycles [do not add here]
    return background_functions() + convolution_functions()


#
def background_functions() -> tuple[str, ...]:
    """
    Get names of all background functions.

    Background functions modify or add to the spectrum generated by peak
    components. They require the current spectrum as input and are applied
    in a specific order during model evaluation.

    Returns
    -------
    tuple of str
        Background function names
    """

    return ("Offset", "Shirley", "LinBack")


#
def energy_functions() -> tuple[str, ...]:
    """
    Get names of all energy/spectral component functions.

    Energy functions define peak shapes and lineshapes used to construct
    spectral models. These include Gaussians, Lorentzians, Voigt profiles,
    and other lineshapes common in spectroscopy.

    Returns
    -------
    tuple of str
        All public function names from energy module
    """

    return tuple(
        name
        for name in dir(fcts_energy)
        if callable(getattr(fcts_energy, name)) and not name.startswith("_")
    )


#
def time_functions() -> tuple[str, ...]:
    """
    Get names of all time dynamics functions.

    Time functions define temporal evolution of parameters in Dynamics models.
    These include exponential decays/rises, oscillations, and other time-domain
    behaviors. Convolution kernels (ending in 'CONV') are excluded as they have
    special handling.

    Returns
    -------
    tuple of str
        Time function names (excluding convolution kernels)
    """

    # Get all function names from functions/time.py excluding convolutions
    return tuple(
        name
        for name in dir(fcts_time)
        if callable(getattr(fcts_time, name))
        and not name.startswith("_")
        and not name.endswith("CONV")
    )


#
def convolution_functions() -> tuple[str, ...]:
    """
    Get names of all convolution kernel functions.

    Convolution functions (kernels) are applied to time-dependent dynamics
    to model instrumental response, broadening, or other time-domain effects.
    These functions are identified by the 'CONV' suffix.

    Returns
    -------
    tuple of str
        Convolution function names ending in 'CONV'
    """

    # Get all function names ending in 'CONV' from functions/time.py
    return tuple(
        name
        for name in dir(fcts_time)
        if callable(getattr(fcts_time, name))
        and name.endswith("CONV")
        and not name.startswith("_")
    )


#
def get_function_parameters(function_name) -> list[str]:
    """
    Get expected parameter names for a function by inspecting its signature.

    Parameters
    ----------
    function_name : str
        Base function name (e.g., 'GLP', 'expFun', 'Shirley')

    Returns
    -------
    list of str
        Parameter names expected by this function
    """

    # Find which module contains this function
    func = None
    for module in [fcts_energy, fcts_time, fcts_profile]:
        if hasattr(module, function_name):
            func = getattr(module, function_name)
            break

    if func is None:
        return []

    # Get function signature
    sig = inspect.signature(func)
    param_names = list(sig.parameters.keys())

    # Remove first parameter (x or t)
    if len(param_names) > 0:
        param_names = param_names[1:]

    # Remove last parameter if it's 'spectrum' (background functions)
    if len(param_names) > 0 and param_names[-1] == "spectrum":
        param_names = param_names[:-1]

    return param_names
