"""Diagnosis model for medical diagnoses."""
from datetime import UTC, datetime
from functools import partial
from typing import Annotated, Literal, Optional

from pydantic import Field, StringConstraints, field_validator

from .base import BaseDocument
from .types import PyObjectId

class Diagnosis(BaseDocument):
    """Diagnosis model representing medical diagnoses."""
    # References
    patientId: PyObjectId = Field(description="ID of the patient")
    practitioner: Annotated[
        str,
        StringConstraints(min_length=1, strip_whitespace=True)
    ] = Field(description="ID of the practitioner who made the diagnosis")

    # Diagnosis details
    icdCode: Annotated[
        str,
        StringConstraints(min_length=1, strip_whitespace=True)
    ] = Field(description="ICD code of the diagnosis")

    isPrediagnosis: bool = Field(
        default=False,
        description="Indicates if this is a pre-diagnosis"
    )
    severity: Literal['mild', 'moderate', 'severe'] = Field(
        default='mild',
        description="Severity of the diagnosis"
    )

    # Additional details
    hospital: Annotated[
        str,
        StringConstraints(min_length=1, strip_whitespace=True)
    ] = Field(description="Hospital where the diagnosis was made")
    hospitalVisit: Optional[PyObjectId] = Field(
        default=None, description="ID of the associated hospital visit, if any"
    )
    diagnosisDate: datetime = Field(
        default_factory=partial(datetime.now, UTC), description="Date of the diagnosis"
    )
    diagnosisClinic: Optional[str] = Field(
        default=None, description="Clinic where the diagnosis was made"
    )
    notes: Optional[str] = Field(
        default=None,
        description="Additional notes regarding the diagnosis"
    )

    @field_validator("icdCode", "hospital", "practitioner")
    @classmethod
    def not_empty(cls, v: str) -> str:
        """Validate that string fields are not empty."""
        v = (v or "").strip()
        if not v:
            raise ValueError("Field cannot be empty")
        return v
