import os
import json
import base64
import hashlib
from datetime import datetime, timedelta
from typing import Optional, List, Dict, Any
import logging

from ..models import (
    FeedGeneratorDescription, FeedSkeletonResponse, FeedSkeletonItem,
    DidDocument, DidDocumentService
)

logger = logging.getLogger(__name__)


class FeedGeneratorService:
    """Service for Bluesky feed generator protocol."""

    def __init__(self):
        self.service_did = os.environ.get("FEED_GENERATOR_SERVICE_DID", "")
        self.feed_key = os.environ.get("FEED_GENERATOR_FEED_KEY", "main-feed")
        self.display_name = os.environ.get("FEED_GENERATOR_DISPLAY_NAME", "My Smart Feed")
        self.description = os.environ.get("FEED_GENERATOR_DESCRIPTION",
                                           "A personalized feed based on your liked posts")
        self.service_url = os.environ.get("FEED_GENERATOR_SERVICE_URL", "")

    def describe(self) -> FeedGeneratorDescription:
        """Get feed generator description."""
        is_configured = bool(self.service_did and self.service_url)

        feed_uri = ""
        if is_configured:
            # The DID in the feed URI is the owner DID, which we don't know until runtime
            # This will be filled in by the frontend
            feed_uri = f"at://<owner-did>/app.bsky.feed.generator/{self.feed_key}"

        return FeedGeneratorDescription(
            feed_uri=feed_uri,
            feed_key=self.feed_key,
            name=self.display_name,
            description=self.description,
            is_configured=is_configured,
            service_did=self.service_did if is_configured else None
        )

    def describe_for_xrpc(self) -> Dict[str, Any]:
        """Get feed description in XRPC format."""
        return {
            "encoding": "application/json",
            "body": {
                "did": self.service_did,
                "feeds": [
                    {
                        "uri": f"at://{self.service_did}/app.bsky.feed.generator/{self.feed_key}",
                        "cid": "bafyreihh6dqzwyoa74a6vulbf6waz7ft3dqbhy5w7fy6t27lf55n5tdigy"  # Dummy CID
                    }
                ],
                "links": {
                    "generator": self.service_url
                }
            }
        }

    def get_did_document(self) -> DidDocument:
        """Get DID document for service identity."""
        if not self.service_did:
            raise InvalidOperationException("Feed generator service not configured")

        return DidDocument(
            id=self.service_did,
            service=[
                DidDocumentService(
                    id="#bsky_fg",
                    type="BskyFeedGenerator",
                    service_endpoint=self.service_url
                )
            ]
        )

    def get_skeleton(self, feed: str, viewer_did: Optional[str],
                     limit: Optional[int] = 50, cursor: Optional[str] = None,
                     store=None) -> FeedSkeletonResponse:
        """Get feed skeleton (list of post URIs)."""
        if not self.service_did:
            raise InvalidOperationException("Feed generator not configured")

        # Parse feed URI to get owner DID
        # at://<did>/app.bsky.feed.generator/<feed_key>
        parts = feed.replace("at://", "").split("/")
        if len(parts) < 3:
            raise InvalidOperationException("Invalid feed URI")

        owner_did = parts[0]
        feed_key = parts[-1]

        if feed_key != self.feed_key:
            raise InvalidOperationException("Feed not found")

        # Get state from store
        if store is None:
            return FeedSkeletonResponse()

        # Default generator
        from ..models import GeneratorDefinition
        definition = GeneratorDefinition(
            id="balanced",
            name="Balanced",
            description="Balanced ranking",
            strategy="hybrid"
        )

        state = store.get_state(owner_did, "balanced", None, definition)

        # Convert to skeleton items
        items = []
        start_idx = int(cursor) if cursor else 0
        end_idx = start_idx + (limit or 50)

        for item in state.items[start_idx:end_idx]:
            items.append(FeedSkeletonItem(post=item.subject_uri))

        next_cursor = str(end_idx) if end_idx < len(state.items) else None

        return FeedSkeletonResponse(
            feed=items,
            cursor=next_cursor
        )


class InvalidOperationException(Exception):
    """Exception for invalid operations."""
    pass
An unhandled error has occurred. Reload 🗙