from dataclasses import dataclass from datetime import datetime from decimal import Decimal from typing import Any, Protocol from uuid import UUID @dataclass(frozen=True) class SourceProduct: source_key: str external_id: str id: UUID category: str brand: str name: str model: str | None variants: tuple["SourceVariant", ...] @dataclass(frozen=True) class SourceVariant: id: UUID name: str manufacturer_sku: str | None identifiers: dict[str, Any] attributes: tuple["SourceAttribute", ...] @dataclass(frozen=True) class SourceAttribute: id: UUID attribute: str raw_value: Any normalized_value: Any unit: str | None normalization_status: str normalizer_version: str confidence: Decimal source_reference: str observed_at: datetime normalization_error: str | None = None @dataclass(frozen=True) class SourceOffer: id: UUID variant_id: UUID external_id: str seller: str url: str | None market: str currency: str condition: str @dataclass(frozen=True) class SourcePriceObservation: id: UUID | None external_offer_id: str external_observation_id: str observed_at: datetime item_price: Decimal shipping_price: Decimal | None currency: str availability: str raw_payload: Any confidence: Decimal class ProductSource(Protocol): source_key: str def get_product(self, external_id: str) -> SourceProduct: ... def get_offers(self, external_product_id: str) -> list[SourceOffer]: ... def get_price_history(self, external_offer_id: str) -> list[SourcePriceObservation]: ... class DiscoverySourceAdapter(Protocol): source_key: str def discover_taxonomy(self, category_ref: str) -> dict[str, Any]: ... def build_query(self, criteria: list[dict[str, Any]], mappings: list[dict[str, Any]]) -> dict[str, Any]: ... def fetch_results(self, query: dict[str, Any], pagination: dict[str, Any]) -> dict[str, Any]: ... def parse_results(self, response: dict[str, Any]) -> list[dict[str, Any]]: ... def normalize_result(self, result: dict[str, Any]) -> dict[str, Any]: ...