"""Type stubs for config module - provides accurate type information for type checkers.

This stub file helps type checkers understand the dynamic code generation in config.py.
"""

from __future__ import annotations

from collections.abc import Callable
from typing import Annotated, ParamSpec, TypeVar, overload

from pydantic import BaseModel

# Re-export constraints from constraints module
from hipr.constraints import (
  Ge as Ge,
)
from hipr.constraints import (
  Gt as Gt,
)
from hipr.constraints import (
  Le as Le,
)
from hipr.constraints import (
  Lt as Lt,
)
from hipr.constraints import (
  MaxLen as MaxLen,
)
from hipr.constraints import (
  MinLen as MinLen,
)
from hipr.constraints import (
  MultipleOf as MultipleOf,
)
from hipr.constraints import (
  Pattern as Pattern,
)

# Type variables
P = ParamSpec("P")
R = TypeVar("R")
T = TypeVar("T")

class _HyperMarker:
  """Internal marker for hyperparameters."""

# Hyper is a type alias that resolves to Annotated[T, _HyperMarker, ...]
type Hyper[T, *Args] = Annotated[T, _HyperMarker, *Args]

class MakeableModel[R](BaseModel):
  """Base class for generated Config models with make() method."""

  def __init__(self, **kwargs: object) -> None: ...
  def make(self) -> Callable[..., R]: ...

class ConfigurableIndicator[**P, R]:
  """Wrapper for @configurable decorated functions with Config class."""

  Config: type[MakeableModel[R]]

  def __init__(
    self, fn: Callable[P, R], config_cls: type[MakeableModel[R]]
  ) -> None: ...
  def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: ...
  def __get__(
    self, obj: object, objtype: type | None = None
  ) -> ConfigurableIndicator[P, R]: ...

# configurable decorator with overloads for functions vs classes
# type[R] is Callable, so overloads overlap - this is intentional
# The overload ensures type[R] returns type[R], not ConfigurableIndicator
@overload
def configurable[R](fn_or_class: type[R]) -> type[R]: ...  # pyright: ignore[reportOverlappingOverload]
@overload
def configurable[**P, R](
  fn_or_class: Callable[P, R],
) -> ConfigurableIndicator[P, R]: ...
def configurable[**P, R](
  fn_or_class: Callable[P, R] | type[R],
) -> ConfigurableIndicator[P, R] | type[R]: ...
