# opticedge_types/types/instant.py

from pydantic import BaseModel, Field, ConfigDict, model_validator
from typing import List, Literal, Optional


# -----------------------------
# Validation block
# -----------------------------

class ValidationResult(BaseModel):
    model_config = ConfigDict(extra="forbid")

    front_back_valid: bool
    same_card_confidence: Literal["high", "medium", "low"]
    image_quality: Literal["good", "borderline", "poor"]
    damage_override_triggered: bool


# -----------------------------
# Subgrades
# -----------------------------

class SubGrades(BaseModel):
    model_config = ConfigDict(extra="forbid")

    centering: float = Field(..., ge=1.0, le=10.0)
    surface: float = Field(..., ge=1.0, le=10.0)
    edges: float = Field(..., ge=1.0, le=10.0)
    corners: float = Field(..., ge=1.0, le=10.0)


# -----------------------------
# Bounding box
# -----------------------------

class BoundingBox(BaseModel):
    model_config = ConfigDict(extra="forbid")

    x: float = Field(..., ge=0.0, le=1.0)
    y: float = Field(..., ge=0.0, le=1.0)
    width: float = Field(..., ge=0.0, le=1.0)
    height: float = Field(..., ge=0.0, le=1.0)


LocationZone = Literal[
    # FRONT
    "front_top_left_corner", "front_top_right_corner",
    "front_bottom_left_corner", "front_bottom_right_corner",
    "front_top_edge_left", "front_top_edge_center", "front_top_edge_right",
    "front_bottom_edge_left", "front_bottom_edge_center", "front_bottom_edge_right",
    "front_left_edge_upper", "front_left_edge_center", "front_left_edge_lower",
    "front_right_edge_upper", "front_right_edge_center", "front_right_edge_lower",
    "front_inner_top_left", "front_inner_top_center", "front_inner_top_right",
    "front_inner_middle_left", "front_inner_middle_center", "front_inner_middle_right",
    "front_inner_bottom_left", "front_inner_bottom_center", "front_inner_bottom_right",

    # BACK
    "back_top_left_corner", "back_top_right_corner",
    "back_bottom_left_corner", "back_bottom_right_corner",
    "back_top_edge_left", "back_top_edge_center", "back_top_edge_right",
    "back_bottom_edge_left", "back_bottom_edge_center", "back_bottom_edge_right",
    "back_left_edge_upper", "back_left_edge_center", "back_left_edge_lower",
    "back_right_edge_upper", "back_right_edge_center", "back_right_edge_lower",
    "back_inner_top_left", "back_inner_top_center", "back_inner_top_right",
    "back_inner_middle_left", "back_inner_middle_center", "back_inner_middle_right",
    "back_inner_bottom_left", "back_inner_bottom_center", "back_inner_bottom_right",
]


class Defect(BaseModel):
    model_config = ConfigDict(extra="forbid")

    defect_type: Literal[
        "corner_whitening",
        "edge_whitening",
        "surface_scratch",
        "holo_or_foil_scratching",
        "crease",
        "foil_wear",
        "edge_chip",
        "corner_rounding",
        "staining_or_ink_bleed",
        "post_factory_dents",
        "scuffing"
    ]

    severity: Literal["minimal", "moderate", "major"]
    confidence: float = Field(..., ge=0.0, le=1.0)
    location_zone: LocationZone
    bbox_norm: BoundingBox
    notes: str = Field(..., min_length=1)


class DefectMap(BaseModel):
    model_config = ConfigDict(extra="forbid")

    front: List[Defect] = Field(default_factory=list)
    back: List[Defect] = Field(default_factory=list)


# ==========================================================
# 🔥 SINGLE MODEL FOR OPENAI
# ==========================================================

class PromptGradingResponse(BaseModel):
    """
    OpenAI-compatible single schema.
    """

    model_config = ConfigDict(extra="forbid")

    submission_status: Literal["REJECTED", "ACCEPTED"]

    # ---- Rejection ----
    rejection_message: Optional[str] = Field(default=None, min_length=10, max_length=200)

    # ---- Accepted ----
    validation: Optional[ValidationResult] = None

    overall_grade: Optional[float] = Field(default=None, ge=1.0, le=10.0)

    front_subgrades: Optional[SubGrades] = None
    back_subgrades: Optional[SubGrades] = None

    environment_score: Optional[int] = Field(default=None, ge=0, le=100)
    accuracy_score: Optional[int] = Field(default=None, ge=0, le=100)

    grading_rationale: Optional[str] = Field(default=None, min_length=5)

    defect_map: Optional[DefectMap] = None

    # ------------------------------------------------------
    # Branch validation (after parse)
    # ------------------------------------------------------

    @model_validator(mode="after")
    def validate_branch(self):
        if self.submission_status == "REJECTED":
            if not self.rejection_message:
                raise ValueError("rejection_message required for REJECTED")
            return self

        if self.submission_status == "ACCEPTED":
            required = [
                self.validation,
                self.overall_grade,
                self.front_subgrades,
                self.back_subgrades,
                self.environment_score,
                self.accuracy_score,
                self.grading_rationale,
                self.defect_map,
            ]
            if any(v is None for v in required):
                raise ValueError("Missing required fields for ACCEPTED")
            return self

        raise ValueError("Invalid submission_status")
