# Structured, stable diagnostics for failed contracts and searches.
from dataclasses import dataclass


@dataclass(frozen=True)
class Diagnostic:
    rule: str
    component: str
    position: tuple | None
    conditions: str

    def __str__(self):
        return f'{self.rule}: {self.component} at {self.position}: {self.conditions}'


class ContractError(ValueError):

    def __init__(self, rule, component='/', position=None, conditions=''):
        self.diagnostic = Diagnostic(rule, component, position, conditions)
        super().__init__(str(self.diagnostic))


class ValidationError(ContractError):

    def __init__(self, diagnostics):
        self.diagnostics = diagnostics
        self.diagnostic = diagnostics[0]
        ValueError.__init__(self, '\n'.join(map(str, diagnostics[:12])))


class SearchExhausted(ContractError):
    pass
