"""Scoring output contract (design §7.6). The model returns findings and ratings, never marks."""
from __future__ import annotations
from typing import Literal
from pydantic import BaseModel, Field

ErrorType = Literal["spelling", "grammar", "factual", "method", "calculation", "missing_key_point",
                    "missing_unit", "label", "irrelevant"]


class KeyPointStatus(BaseModel):
    key_point_id: str
    status: Literal["present", "partial", "absent"]
    line_ref: str | None = None


class ErrorItem(BaseModel):
    type: ErrorType
    line_ref: str | None = None          # element id the error is on
    as_written: str | None = None
    correction: str | None = None
    remark: str = Field(max_length=120)  # spec says ≤60 chars; trimmed in code, lenient here
    key_point_id: str | None = None


class PositiveItem(BaseModel):
    line_ref: str | None = None
    key_point_id: str | None = None
    remark: str | None = None


class UnitFinding(BaseModel):
    unit_id: str
    correctness: float = Field(ge=0, le=1)
    completeness: float = Field(ge=0, le=1)
    key_points: list[KeyPointStatus] = Field(default_factory=list)
    error_items: list[ErrorItem] = Field(default_factory=list)
    positive_items: list[PositiveItem] = Field(default_factory=list)
    brief: str
    detailed: str


class ScriptFinding(BaseModel):
    units: list[UnitFinding]
    strengths: list[str] = Field(default_factory=list)
    weaknesses: list[str] = Field(default_factory=list)
    suggestions: list[str] = Field(default_factory=list)
    summary: str = ""


class UnitsOnlyFinding(BaseModel):
    """Used for per-question / rescore calls where script feedback is not requested."""
    units: list[UnitFinding]


class ScriptFeedback(BaseModel):
    """Follow-up call when a long script was split (SC-20)."""
    strengths: list[str]
    weaknesses: list[str]
    suggestions: list[str]
    summary: str
