from datetime import date, datetime
from pydantic import BaseModel, ConfigDict, EmailStr, Field, model_validator
from .models import EntryKind


class Register(BaseModel):
    email: EmailStr
    password: str = Field(min_length=12, max_length=128)


class Token(BaseModel):
    access_token: str
    token_type: str = "bearer"


class ProfileIn(BaseModel):
    display_name: str | None = Field(None, max_length=80)
    birth_date: date | None = None
    height_cm: float | None = Field(None, ge=80, le=250)
    objective: str | None = Field(None, max_length=120)
    health_context: str | None = Field(None, max_length=1000)
    consent_health_data: bool = False


class ProfileOut(ProfileIn):
    user_id: str
    updated_at: datetime
    model_config = ConfigDict(from_attributes=True)


RANGES = {
    EntryKind.weight: (20, 500), EntryKind.glucose: (20, 600), EntryKind.water: (0, 15000),
    EntryKind.activity: (0, 1440), EntryKind.sleep: (0, 24), EntryKind.mood: (1, 5),
    EntryKind.meal: (0, 10000),
}


class EntryIn(BaseModel):
    kind: EntryKind
    value: float
    unit: str = Field(min_length=1, max_length=24)
    note: str | None = Field(None, max_length=500)
    recorded_at: datetime | None = None

    @model_validator(mode="after")
    def sensible_range(self):
        if self.kind == EntryKind.glucose:
            glucose_ranges = {"mg/dL": (20, 600), "mmol/L": (1.1, 33.3)}
            if self.unit not in glucose_ranges:
                raise ValueError("glucose unit must be mg/dL or mmol/L")
            low, high = glucose_ranges[self.unit]
        else:
            low, high = RANGES[self.kind]
        if not low <= self.value <= high:
            raise ValueError(f"value must be between {low} and {high} for {self.kind.value}")
        return self


class EntryOut(EntryIn):
    id: str
    user_id: str
    recorded_at: datetime
    created_at: datetime
    model_config = ConfigDict(from_attributes=True)


class CoachMessage(BaseModel):
    role: str = Field(pattern="^(user|assistant)$")
    content: str = Field(min_length=1, max_length=2000)


class CoachChatIn(BaseModel):
    message: str = Field(min_length=1, max_length=2000)
    history: list[CoachMessage] = Field(default_factory=list, max_length=12)


class CoachChatOut(BaseModel):
    assistant: str = "Peg"
    message: str
    source: str = Field(description="model, safety, or fallback")
    medical_notice: str = "Conseils généraux uniquement — Peg ne remplace pas un professionnel de santé."
