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


# -------------------------
# 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)


# -------------------------
# Defects
# -------------------------

class BBox(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",
        "print_line",
        "indentation",
        "pressure_mark",
        "binder_dent",
        "warping",
        "layer_separation"
    ]

    severity: Literal["minimal", "moderate", "major"]

    confidence: float = Field(..., ge=0.0, le=1.0)

    location_zone: LocationZone

    bbox_norm: BBox

    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)


# -------------------------
# Final Grading Result
# -------------------------

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

    validation: ValidationResult

    overall_grade: float = Field(..., ge=1.0, le=10.0)

    front_subgrades: SubGrades
    back_subgrades: SubGrades

    environment_score: int = Field(..., ge=0, le=100)
    accuracy_score: int = Field(..., ge=0, le=100)

    grading_rationale: str = Field(..., min_length=5)

    defect_map: DefectMap
