"""Provider pattern for producing percolate-compatible entities from data sources.

BaseProvider defines the interface. FeedProvider is the built-in implementation
that runs the feed pipeline and converts Items to P8Resources + P8Moments.
"""

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

from platoon.models import Item, P8Moment, P8Resource


@dataclass
class ProviderResult:
    """Output of a provider run."""

    resources: List[P8Resource] = field(default_factory=list)
    moments: List[P8Moment] = field(default_factory=list)
    items: List[Item] = field(default_factory=list)

    @property
    def total(self) -> int:
        return len(self.resources) + len(self.moments)

    def to_export_dicts(self) -> dict:
        """Return JSON-serializable dicts for p8 upsert."""
        return {
            "resources": [r.to_upsert_dict() for r in self.resources],
            "moments": [m.to_upsert_dict() for m in self.moments],
        }


class BaseProvider(ABC):
    """Abstract provider that emits percolate entities."""

    name: str = "base"

    @abstractmethod
    def run(self, config: dict, user_id: Optional[UUID] = None) -> ProviderResult:
        """Run the provider and return percolate-compatible entities."""
        ...


class FeedProvider(BaseProvider):
    """Built-in provider that runs the feed pipeline.

    Fetches from configured sources, scores, enriches images,
    and converts Items to P8Resources with a digest P8Moment.
    """

    name = "feed"

    def __init__(self, tavily_key: Optional[str] = None):
        self.tavily_key = tavily_key

    def run(self, config: dict, user_id: Optional[UUID] = None) -> ProviderResult:
        """Run the full feed pipeline and convert to percolate entities.

        Args:
            config: Resolved profile config (from resolve_profile()).
            user_id: User UUID for entity ownership and deterministic IDs.

        Returns:
            ProviderResult with P8Resources (one per article) and a digest P8Moment.
        """
        from platoon.cli import _fetch_and_score
        from platoon.fetcher import Fetcher
        from platoon.images import enrich_images

        fetcher = Fetcher(config.get("fetcher", {}))

        try:
            scored_items = _fetch_and_score(
                config, source_filter=None, fetcher=fetcher, tavily_key=self.tavily_key
            )
            enrich_images(scored_items, fetcher)
        finally:
            fetcher.close()

        return self.items_to_result(scored_items, config, user_id)

    def items_to_result(
        self,
        items: List[Item],
        config: dict,
        user_id: Optional[UUID] = None,
    ) -> ProviderResult:
        """Convert scored Items to a ProviderResult (without running the pipeline).

        Useful when you already have scored items and just need the conversion.
        """
        profile_name = config.get("profile_name", "default")

        resources = [P8Resource.from_item(item, user_id=user_id) for item in items]

        moment = P8Moment.from_digest(
            profile_name=profile_name,
            resources=resources,
            user_id=user_id,
        )

        return ProviderResult(resources=resources, moments=[moment], items=items)
