"""StatisticalModel: the result of a ConceptualModel.query() call.

Python-native result object (rTisane generates R scripts instead).
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any

from .inference.random_effects import RandomEffect, RandomEffectGroup


@dataclass
class StatisticalModel:
    """Inferred statistical model specification."""

    dv: str
    iv: str
    main_effects: list[str]
    interaction_effects: list[str] = field(default_factory=list)
    random_effects: list[RandomEffect | RandomEffectGroup] = field(default_factory=list)
    family_candidates: dict[str, list[str]] = field(default_factory=dict)
    family: str = ""
    link: str | None = None

    def formula(self) -> str:
        """Return an R-style formula string.

        Example: ``"DV ~ IV + Confounder + (1 | Group)"``
        """
        parts: list[str] = list(self.main_effects)
        parts.extend(self.interaction_effects)

        re_parts = [str(re) for re in self.random_effects]
        parts.extend(re_parts)

        rhs = " + ".join(parts) if parts else "1"
        return f"{self.dv} ~ {rhs}"

    def summary(self) -> dict[str, Any]:
        """Machine-readable summary of the model."""
        return {
            "dv": self.dv,
            "iv": self.iv,
            "main_effects": self.main_effects,
            "interaction_effects": self.interaction_effects,
            "random_effects": [str(re) for re in self.random_effects],
            "family": self.family,
            "link": self.link,
            "family_candidates": {
                f: list(links) for f, links in self.family_candidates.items()
            },
        }

    def with_family(self, family: str, link: str | None = None) -> "StatisticalModel":
        """Return a copy with overridden family/link selection."""
        if family not in self.family_candidates:
            raise ValueError(
                f"Family {family!r} not in candidates: {list(self.family_candidates)}"
            )
        if link is None:
            links = self.family_candidates[family]
            link = links[0] if links else None
        return StatisticalModel(
            dv=self.dv,
            iv=self.iv,
            main_effects=list(self.main_effects),
            interaction_effects=list(self.interaction_effects),
            random_effects=list(self.random_effects),
            family_candidates=dict(self.family_candidates),
            family=family,
            link=link,
        )
