"""Confidence scoring models used throughout the semantic model."""

from enum import Enum

from pydantic import Field, field_validator

from semantic_model.base import SemanticBaseModel


class ConfidenceObjectType(str, Enum):
    """Types of objects that can have confidence scores."""

    TABLE = "table"
    COLUMN = "column"
    RELATIONSHIP = "relationship"
    ENTITY = "entity"
    ATTRIBUTE = "attribute"
    SOURCE = "source"


class LowConfidenceItem(SemanticBaseModel):
    """Identifies an item with low confidence that may need expert review."""

    object_type: ConfidenceObjectType
    object_id: str = Field(..., description="ID of the low-confidence object")
    object_name: str = Field(..., description="Human-readable name for display")
    score: float = Field(..., ge=0.0, le=1.0, description="Confidence score")
    reason: str = Field(..., description="Why confidence is low")
    suggested_clarification: str = Field(
        default="",
        description="What we'd ask the expert to clarify",
    )


class ConfidenceScore(SemanticBaseModel):
    """Confidence scoring for semantic model elements.

    Scores range from 0.0 (no confidence) to 1.0 (fully confident).
    """

    overall: float = Field(
        ...,
        ge=0.0,
        le=1.0,
        description="Overall confidence score",
    )

    # Component scores (optional, for detailed breakdown)
    schema_understanding: float | None = Field(
        default=None,
        ge=0.0,
        le=1.0,
        description="Confidence in understanding the schema structure",
    )
    semantic_typing: float | None = Field(
        default=None,
        ge=0.0,
        le=1.0,
        description="Confidence in semantic type assignments",
    )
    relationship_detection: float | None = Field(
        default=None,
        ge=0.0,
        le=1.0,
        description="Confidence in detected relationships",
    )
    description_quality: float | None = Field(
        default=None,
        ge=0.0,
        le=1.0,
        description="Quality of generated descriptions",
    )

    # Threshold comparison
    threshold: float = Field(
        default=0.7,
        ge=0.0,
        le=1.0,
        description="Configured threshold for this element",
    )

    # Items dragging down the score
    low_confidence_items: list[LowConfidenceItem] = Field(
        default_factory=list,
        description="Items with low confidence needing review",
    )

    @property
    def meets_threshold(self) -> bool:
        """Check if overall confidence meets the threshold."""
        return self.overall >= self.threshold

    @field_validator("overall", mode="before")
    @classmethod
    def round_overall(cls, v: float) -> float:
        """Round to 3 decimal places."""
        return round(v, 3)

    def with_component_scores(
        self,
        schema_understanding: float | None = None,
        semantic_typing: float | None = None,
        relationship_detection: float | None = None,
        description_quality: float | None = None,
    ) -> "ConfidenceScore":
        """Create a new score with component scores and computed overall."""
        components = [
            c
            for c in [
                schema_understanding,
                semantic_typing,
                relationship_detection,
                description_quality,
            ]
            if c is not None
        ]

        overall = sum(components) / len(components) if components else self.overall

        return self.model_copy(
            update={
                "overall": round(overall, 3),
                "schema_understanding": schema_understanding,
                "semantic_typing": semantic_typing,
                "relationship_detection": relationship_detection,
                "description_quality": description_quality,
            }
        )


def create_confidence(
    overall: float,
    threshold: float = 0.7,
    low_confidence_items: list[LowConfidenceItem] | None = None,
) -> ConfidenceScore:
    """Factory function to create a confidence score."""
    return ConfidenceScore(
        overall=overall,
        threshold=threshold,
        low_confidence_items=low_confidence_items or [],
    )
