"""Data models for feed items and percolate-compatible entities."""

from dataclasses import dataclass, field
from datetime import datetime
from typing import Dict, List, Optional
from uuid import UUID, uuid4, uuid5

from pydantic import BaseModel, Field

# Matches percolate's P8_NAMESPACE for deterministic UUIDs
P8_NAMESPACE = UUID("12345678-1234-5678-1234-567812345678")


# ---------------------------------------------------------------------------
# User Profile (mirrors p8k8 UserMetadata)
# ---------------------------------------------------------------------------


class UserProfile(BaseModel):
    """User profile — mirrors p8k8 UserMetadata user-specific fields.

    See p8k8 UserMetadata for the canonical schema definition.
    Sources are global config, not per-user — see config.DEFAULT_SOURCES.
    """

    profile_name: str = "default"

    # --- UserMetadata fields (user-specific) ---
    relations: Optional[List[Dict]] = None
    interests: List[str] = Field(default_factory=list)
    feeds: Optional[List[Dict]] = None
    preferences: Optional[Dict] = None
    facts: Optional[Dict] = None
    categories: Dict = Field(default_factory=dict)  # {name: {keywords, weight, color}}

    def to_config_dict(self) -> dict:
        """User fields as a flat dict for pipeline functions."""
        return {
            "profile_name": self.profile_name,
            "interests": self.interests,
            "categories": self.categories,
        }


# ---------------------------------------------------------------------------
# Feed Item (internal pipeline model)
# ---------------------------------------------------------------------------

@dataclass
class Item:
    title: str
    url: str
    source: str
    summary: str = ""
    score: float = 0.0
    category: str = "Uncategorised"
    tags: list = field(default_factory=list)
    image_url: str = ""
    engagement: dict = field(default_factory=dict)
    # engagement keys: upvotes, comments, stars, citations

    def to_dict(self) -> dict:
        return {
            "title": self.title,
            "url": self.url,
            "source": self.source,
            "summary": self.summary,
            "score": round(self.score, 3),
            "category": self.category,
            "tags": self.tags,
            "image_url": self.image_url,
            "engagement": self.engagement,
        }


# ---------------------------------------------------------------------------
# Percolate-compatible entities
# ---------------------------------------------------------------------------

def deterministic_id(table: str, key: str, user_id: Optional[UUID] = None) -> UUID:
    """Generate a deterministic UUID5 matching percolate's scheme."""
    seed = f"{table}:{key}"
    if user_id:
        seed += f":{user_id}"
    return uuid5(P8_NAMESPACE, seed)


class P8Resource(BaseModel):
    """Maps to percolate's resources table. One per article/item."""

    id: UUID = Field(default_factory=uuid4)
    name: str
    uri: Optional[str] = None
    content: Optional[str] = None
    category: Optional[str] = None
    image_uri: Optional[str] = None
    comment: Optional[str] = None
    rating: Optional[int] = None
    related_entities: List[str] = Field(default_factory=list)

    # CoreModel fields
    user_id: Optional[UUID] = None
    metadata: Dict = Field(default_factory=dict)
    tags: List[str] = Field(default_factory=list)
    graph_edges: List[Dict] = Field(default_factory=list)
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)

    @classmethod
    def from_item(cls, item: "Item", user_id: Optional[UUID] = None) -> "P8Resource":
        """Convert a scored feed Item into a percolate Resource."""
        source_tag = item.source.lower().replace(" ", "_")
        tags = sorted(set([source_tag, "news"] + item.tags))

        entity_id = deterministic_id("resources", item.url or item.title, user_id)

        return cls(
            id=entity_id,
            name=item.title,
            uri=item.url,
            content=item.summary[:2000] if item.summary else None,
            category="news",
            image_uri=item.image_url or None,
            user_id=user_id,
            tags=tags,
            metadata={
                "score": round(item.score, 3),
                "feed_category": item.category,
                "source": item.source,
                "engagement": item.engagement,
            },
        )

    def to_upsert_dict(self) -> dict:
        """Serialize for percolate upsert (JSON-safe dict)."""
        d = self.model_dump(mode="json")
        d["id"] = str(self.id)
        if self.user_id:
            d["user_id"] = str(self.user_id)
        d["created_at"] = self.created_at.isoformat()
        d["updated_at"] = self.updated_at.isoformat()
        return d


class P8Moment(BaseModel):
    """Maps to percolate's moments table. One per digest run."""

    id: UUID = Field(default_factory=uuid4)
    name: str
    moment_type: str = "digest"
    summary: Optional[str] = None
    rating: Optional[int] = None

    # CoreModel fields
    user_id: Optional[UUID] = None
    metadata: Dict = Field(default_factory=dict)
    tags: List[str] = Field(default_factory=list)
    graph_edges: List[Dict] = Field(default_factory=list)
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)

    @classmethod
    def from_digest(
        cls,
        profile_name: str,
        resources: List["P8Resource"],
        user_id: Optional[UUID] = None,
    ) -> "P8Moment":
        """Create a digest moment linking to produced resources."""
        date_str = datetime.utcnow().strftime("%Y-%m-%d")
        name = f"feed-digest-{profile_name}-{date_str}"
        entity_id = deterministic_id("moments", name, user_id)

        source_counts: dict = {}
        category_counts: dict = {}
        for r in resources:
            src = r.metadata.get("source", "unknown")
            cat = r.metadata.get("feed_category", "unknown")
            source_counts[src] = source_counts.get(src, 0) + 1
            category_counts[cat] = category_counts.get(cat, 0) + 1

        edges = [
            {"source": str(entity_id), "target": str(r.id), "relation": "contains"}
            for r in resources
        ]

        return cls(
            id=entity_id,
            name=name,
            moment_type="digest",
            summary=f"Processed {len(resources)} resources from {len(source_counts)} sources for profile '{profile_name}'",
            user_id=user_id,
            tags=["digest", "news", profile_name],
            graph_edges=edges,
            metadata={
                "profile": profile_name,
                "total_items": len(resources),
                "source_counts": source_counts,
                "category_counts": category_counts,
                "date": date_str,
            },
        )

    def to_upsert_dict(self) -> dict:
        """Serialize for percolate upsert (JSON-safe dict)."""
        d = self.model_dump(mode="json")
        d["id"] = str(self.id)
        if self.user_id:
            d["user_id"] = str(self.user_id)
        d["created_at"] = self.created_at.isoformat()
        d["updated_at"] = self.updated_at.isoformat()
        return d
