"""FlexOHR base error hierarchy.

Paradigm modules register their own errors via ``register_paradigm_errors()``.
All FlexOHR exceptions multi-inherit from the corresponding built-in type
so that ``except TypeError`` etc. still catches them.
"""

from __future__ import annotations


class FlexohrError(Exception):
    """Base exception for all FlexOHR errors."""

    default_message: str = "FlexOHR error"

    def __init__(self, message: str | None = None) -> None:
        self.detail = message
        msg = f"{self.default_message}: {message}" if message else self.default_message
        super().__init__(msg)


class FlexohrTypeError(FlexohrError, TypeError):
    default_message = "FlexOHR type error"


class FlexohrValueError(FlexohrError, ValueError):
    default_message = "FlexOHR value error"


class InvalidComponentValue(FlexohrValueError):
    default_message = "Invalid component value"


class ImmutabilityError(FlexohrError, AttributeError):
    default_message = "Cannot modify frozen FlexOHR object"


class ValidationError(FlexohrError):
    default_message = "Validation failed"


class CodecRegistryError(FlexohrError, KeyError):
    default_message = "Codec registry lookup failed"

    def __init__(self, message: str | None = None) -> None:  # noqa: B042
        # KeyError.__init__ expects a single key arg; route through FlexohrError
        FlexohrError.__init__(self, message)


# ── Paradigm registration ──

_paradigm_errors: dict[str, list[type[FlexohrError]]] = {}


def register_paradigm_errors(paradigm_name: str, *error_classes: type[FlexohrError]) -> None:
    """Register paradigm-specific error classes for discovery."""
    _paradigm_errors.setdefault(paradigm_name, []).extend(error_classes)


def get_paradigm_errors(paradigm_name: str) -> list[type[FlexohrError]]:
    """Retrieve registered error classes for a paradigm."""
    return list(_paradigm_errors.get(paradigm_name, []))
