""" Schemas API FastAPI pour Phase 3. """ from datetime import datetime from typing import Optional from pydantic import BaseModel, Field class HealthStatus(BaseModel): db: bool redis: bool class ProductHistoryPoint(BaseModel): price: float fetched_at: datetime class ProductOut(BaseModel): id: int source: str reference: str url: str title: Optional[str] = None category: Optional[str] = None description: Optional[str] = None currency: Optional[str] = None msrp: Optional[float] = None first_seen_at: datetime last_updated_at: datetime latest_price: Optional[float] = None latest_shipping_cost: Optional[float] = None latest_stock_status: Optional[str] = None latest_fetched_at: Optional[datetime] = None images: list[str] = [] specs: dict[str, str] = {} discount_amount: Optional[float] = None discount_percent: Optional[float] = None history: list[ProductHistoryPoint] = Field(default_factory=list) class ProductCreate(BaseModel): source: str reference: str url: str title: Optional[str] = None category: Optional[str] = None description: Optional[str] = None currency: Optional[str] = None msrp: Optional[float] = None class ProductUpdate(BaseModel): url: Optional[str] = None title: Optional[str] = None category: Optional[str] = None description: Optional[str] = None currency: Optional[str] = None msrp: Optional[float] = None class PriceHistoryOut(BaseModel): id: int product_id: int price: Optional[float] = None shipping_cost: Optional[float] = None stock_status: Optional[str] = None fetch_method: str fetch_status: str fetched_at: datetime class PriceHistoryCreate(BaseModel): product_id: int price: Optional[float] = None shipping_cost: Optional[float] = None stock_status: Optional[str] = None fetch_method: str fetch_status: str fetched_at: datetime class PriceHistoryUpdate(BaseModel): price: Optional[float] = None shipping_cost: Optional[float] = None stock_status: Optional[str] = None fetch_method: Optional[str] = None fetch_status: Optional[str] = None fetched_at: Optional[datetime] = None class ScrapingLogOut(BaseModel): id: int product_id: Optional[int] = None url: str source: str reference: Optional[str] = None fetch_method: str fetch_status: str fetched_at: datetime duration_ms: Optional[int] = None html_size_bytes: Optional[int] = None errors: Optional[list[str]] = None notes: Optional[list[str]] = None class WebhookOut(BaseModel): id: int event: str url: str enabled: bool secret: Optional[str] = None created_at: datetime class WebhookCreate(BaseModel): event: str url: str enabled: bool = True secret: Optional[str] = None class WebhookUpdate(BaseModel): event: Optional[str] = None url: Optional[str] = None enabled: Optional[bool] = None secret: Optional[str] = None class WebhookTestResponse(BaseModel): status: str class ScrapingLogCreate(BaseModel): product_id: Optional[int] = None url: str source: str reference: Optional[str] = None fetch_method: str fetch_status: str fetched_at: datetime duration_ms: Optional[int] = None html_size_bytes: Optional[int] = None errors: Optional[list[str]] = None notes: Optional[list[str]] = None class ScrapingLogUpdate(BaseModel): product_id: Optional[int] = None url: Optional[str] = None source: Optional[str] = None reference: Optional[str] = None fetch_method: Optional[str] = None fetch_status: Optional[str] = None fetched_at: Optional[datetime] = None duration_ms: Optional[int] = None html_size_bytes: Optional[int] = None errors: Optional[list[str]] = None notes: Optional[list[str]] = None class EnqueueRequest(BaseModel): url: str = Field(..., description="URL du produit") use_playwright: Optional[bool] = None save_db: bool = True class EnqueueResponse(BaseModel): job_id: str class ScheduleRequest(BaseModel): url: str = Field(..., description="URL du produit") interval_hours: int = Field(default=24, ge=1) use_playwright: Optional[bool] = None save_db: bool = True class ScheduleResponse(BaseModel): job_id: str next_run: datetime class ScrapePreviewRequest(BaseModel): url: str use_playwright: Optional[bool] = None class ScrapePreviewResponse(BaseModel): success: bool snapshot: Optional[dict[str, object]] = None error: Optional[str] = None class ScrapeCommitRequest(BaseModel): snapshot: dict[str, object] class ScrapeCommitResponse(BaseModel): success: bool product_id: Optional[int] = None error: Optional[str] = None class VersionResponse(BaseModel): api_version: str class BackendLogEntry(BaseModel): time: datetime level: str message: str class UvicornLogEntry(BaseModel): line: str