"""
Declarative schemas for template-based training evaluation (Layer 1 scaffold).

Templates select built-in algorithms by id and pass parameters; they do not embed
executable logic. See resolver and algorithm registry.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Dict, List, Mapping, Optional


@dataclass(frozen=True)
class FocusAreaMapping:
    """Maps a share of one dimension's score to a Focus Area (by stable key)."""

    focus_area_key: str
    weight: float


@dataclass(frozen=True)
class DimensionSpec:
    """
    One evaluation dimension: algorithm + inputs + params + FA mapping.

    inputs: names of keys expected in the flat activity_inputs dict passed to the resolver.
    """

    key: str
    algorithm_id: str
    inputs: tuple[str, ...]
    params: Mapping[str, Any]
    maps_to: tuple[FocusAreaMapping, ...]


@dataclass(frozen=True)
class CalculationTemplate:
    """Declarative multi-dimensional calculation template (in-code registry)."""

    id: str
    version: str
    label: str
    dimensions: tuple[DimensionSpec, ...]


@dataclass(frozen=True)
class TrainingBaseProfile:
    """
    Conceptual base profile: links a training context to a default template.

    allowed_dimension_keys: if set, dimensions not listed are skipped at resolve time.
    """

    key: str
    label: str
    default_template_id: str
    allowed_dimension_keys: Optional[frozenset[str]] = None


@dataclass
class AlgorithmRunResult:
    """Output of a single built-in algorithm execution."""

    raw_score: float
    normalized_score: float
    missing_inputs: List[str]
    detail: Dict[str, Any] = field(default_factory=dict)


@dataclass
class DimensionResult:
    """Per-dimension result after resolution."""

    dimension_key: str
    algorithm_id: str
    raw_score: float
    normalized_score: float
    missing_inputs: List[str]
    evidence: Dict[str, Any] = field(default_factory=dict)


@dataclass
class TrainingEvaluationResult:
    """
    Stable structured result for Layer 2 (KI, charts, APIs, future persistence).

    focus_area_contributions: aggregated contribution per focus_area key (additive).
    """

    template_id: str
    template_version: str
    base_profile_key: Optional[str]
    dimension_results: List[DimensionResult]
    focus_area_contributions: Dict[str, float]
    confidence: str
    evidence: Dict[str, Any]
    trace: Optional[Dict[str, Any]] = None

    def to_serializable(self) -> Dict[str, Any]:
        """JSON-compatible dict (for APIs / storage)."""
        return {
            "template_id": self.template_id,
            "template_version": self.template_version,
            "base_profile_key": self.base_profile_key,
            "dimension_results": [
                {
                    "dimension_key": d.dimension_key,
                    "algorithm_id": d.algorithm_id,
                    "raw_score": d.raw_score,
                    "normalized_score": d.normalized_score,
                    "missing_inputs": d.missing_inputs,
                    "evidence": d.evidence,
                }
                for d in self.dimension_results
            ],
            "focus_area_contributions": dict(self.focus_area_contributions),
            "confidence": self.confidence,
            "evidence": self.evidence,
            "trace": self.trace,
        }
