"""Root-finding interfaces and result/config types."""

from __future__ import annotations

from dataclasses import dataclass, replace
from typing import Protocol, runtime_checkable

DEFAULT_TOLERANCE: float = 1e-10
DEFAULT_MAX_ITERATIONS: int = 100


@dataclass(frozen=True, slots=True)
class SolverConfig:
    tolerance: float = DEFAULT_TOLERANCE
    max_iterations: int = DEFAULT_MAX_ITERATIONS

    def with_tolerance(self, tolerance: float) -> "SolverConfig":
        return replace(self, tolerance=float(tolerance))

    def with_max_iterations(self, max_iterations: int) -> "SolverConfig":
        return replace(self, max_iterations=int(max_iterations))


@dataclass(frozen=True, slots=True)
class SolverResult:
    root: float
    iterations: int
    residual: float
    converged: bool


@runtime_checkable
class RootFinder(Protocol):
    def find_root(self, f, *args, **kwargs) -> SolverResult:  # pragma: no cover - protocol
        ...


# Public aliases for solver results and interfaces.
MathResult = SolverResult
Solver = RootFinder


__all__ = [
    "DEFAULT_TOLERANCE",
    "DEFAULT_MAX_ITERATIONS",
    "SolverConfig",
    "SolverResult",
    "MathResult",
    "RootFinder",
    "Solver",
]
