"""Base data provider interface for external source integrations.

A DataProvider reads records from an external system (Shopify, Stripe, etc.)
and returns them as standard Pydantic schema instances. It handles:
    - Authentication with the external API
    - Incremental fetching using watermarks (last sync timestamp)
    - Rate limit awareness
    - Mapping vendor-specific responses to standard schema

Usage:
    provider = ShopifyProvider(config)
    result = await provider.fetch("products", since=last_watermark)
    # result.records: list of Product pydantic models
    # result.watermark: new high-water mark for next sync
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Dict, List, Optional
from uuid import UUID

from pydantic import BaseModel


@dataclass
class DataProviderResult:
    """Output of a single provider fetch operation.

    Attributes:
        records: List of Pydantic model instances (Products, Orders, etc.)
        watermark: The new high-water mark timestamp for incremental sync.
                   Store this and pass as `since` on the next fetch.
        entity_type: What was fetched (e.g. "products", "orders")
        raw_count: Number of raw records before transform (for diagnostics)
        errors: Any non-fatal errors encountered during fetch/transform
    """

    records: List[BaseModel] = field(default_factory=list)
    watermark: Optional[datetime] = None
    entity_type: str = ""
    raw_count: int = 0
    errors: List[str] = field(default_factory=list)

    @property
    def count(self) -> int:
        return len(self.records)


class DataProvider(ABC):
    """Abstract base for external data source integrations.

    Subclasses implement fetch() for each entity type they support.
    The pipeline runner calls fetch() with the last watermark and
    receives transformed records in standard schema.

    Example subclass:
        class ShopifyProvider(DataProvider):
            name = "shopify"
            entity_types = ["products", "orders", "customers", "inventory"]

            async def fetch(self, entity_type, since=None, config=None):
                raw = await self.client.query(entity_type, updated_after=since)
                records = [Product.from_shopify(r) for r in raw]
                return DataProviderResult(records=records, watermark=max_updated_at)
    """

    name: str = "base"
    entity_types: List[str] = []

    @abstractmethod
    async def fetch(
        self,
        entity_type: str,
        since: Optional[datetime] = None,
        config: Optional[Dict[str, Any]] = None,
    ) -> DataProviderResult:
        """Fetch records of the given entity type, optionally since a watermark.

        Args:
            entity_type: What to fetch — must be in self.entity_types
            since: Only fetch records updated/created after this timestamp.
                   None means full sync.
            config: Optional per-call config overrides

        Returns:
            DataProviderResult with transformed records and new watermark.
        """
        ...

    @abstractmethod
    async def check_connection(self) -> bool:
        """Verify the provider can reach the external API. Used for health checks."""
        ...

    def supported_entities(self) -> List[str]:
        """List entity types this provider can fetch."""
        return self.entity_types
