"""Fediverse client service for fetching hashtag timelines."""

import asyncio
import logging
from datetime import datetime
from typing import Any
from typing import Dict
from typing import List
from typing import Optional

import httpx
from minimal_activitypub.client_2_server import ActivityPub

from fenliu.config import settings

logger = logging.getLogger(__name__)


class FediverseClient:
    """Client for interacting with Fediverse instances."""

    def __init__(self, instance: Optional[str] = None) -> None:
        """Initialize Fediverse client.

        Args:
            instance: Fediverse instance domain (e.g., "mastodon.social").
                      Uses default from settings if not provided.

        """
        self.instance = instance or settings.default_instance

        httpx_client = httpx.AsyncClient(timeout=settings.api_timeout)
        self.client = ActivityPub(instance=self.instance, client=httpx_client)
        self._rate_limit_delay = settings.rate_limit_delay
        self._initialized = False

    async def _ensure_initialized(self) -> None:
        """Ensure the ActivityPub client is initialized."""
        if not self._initialized:
            await self.client.determine_instance_type()
            self._initialized = True

    async def close(self) -> None:
        """Close the HTTP client."""
        await self.client.client.aclose()

    async def fetch_hashtag_timeline(
        self,
        hashtag: str,
        limit: int = 20,
        min_id: Optional[str] = None,
        max_id: Optional[str] = None,
    ) -> List[Dict[str, Any]]:
        """Fetch posts for a specific hashtag.

        Args:
            hashtag: Hashtag to fetch (without #).
            limit: Maximum number of posts to fetch.
            min_id: Return results newer than this ID.
            max_id: Return results older than this ID.

        Returns:
            List of post dictionaries.

        """
        try:
            # Ensure client is initialized
            await self._ensure_initialized()

            # Clean hashtag (remove # if present)
            hashtag = hashtag.lstrip("#").strip()
            if not hashtag:
                logger.warning("Empty hashtag provided")
                return []

            logger.info(f"Fetching #{hashtag} from {self.instance} (limit: {limit})")

            # Apply rate limiting delay
            if self._rate_limit_delay > 0:
                await asyncio.sleep(self._rate_limit_delay)

            # Fetch posts from Fediverse
            posts = await self.client.get_hashtag_timeline(
                hashtag=hashtag,
                limit=limit,
                min_id=min_id,
                max_id=max_id,
            )

            logger.info(f"Fetched {len(posts)} posts for #{hashtag} from {self.instance}")
            return posts

        except Exception as e:
            logger.error(f"Error fetching #{hashtag} from {self.instance}: {e}")
            return []

    def extract_post_data(self, post: Dict[str, Any]) -> Dict[str, Any]:
        """Extract relevant data from a Fediverse post.

        Args:
            post: Raw post data from Fediverse API.

        Returns:
            Dictionary with extracted post data.

        """
        try:
            # Extract basic information
            post_id = post.get("id", "")
            content = post.get("content", "")
            created_at = post.get("created_at")

            # Parse created_at if it's a string
            if isinstance(created_at, str):
                try:
                    created_at = datetime.fromisoformat(created_at.replace("Z", "+00:00"))
                except (ValueError, AttributeError):
                    created_at = None

            # Extract author information
            account = post.get("account", {})
            author_username = account.get("username", "")
            author_display_name = account.get("display_name", "")
            author_url = account.get("url", "")

            # Extract hashtags from content or tags
            hashtags = []
            tags = post.get("tags", [])
            for tag in tags:
                if isinstance(tag, dict) and tag.get("name"):
                    hashtags.append(tag["name"])

            # Extract engagement metrics
            boosts = post.get("reblogs_count", 0)
            likes = post.get("favourites_count", 0)
            replies = post.get("replies_count", 0)

            # Extract URL
            url = post.get("url", "")

            return {
                "post_id": post_id,
                "content": content,
                "author_username": author_username,
                "author_display_name": author_display_name,
                "author_url": author_url,
                "hashtags": hashtags,
                "boosts": boosts,
                "likes": likes,
                "replies": replies,
                "url": url,
                "created_at": created_at,
                "raw_data": post,  # Keep raw data for debugging
            }

        except Exception as e:
            logger.error(f"Error extracting post data: {e}")
            return {}

    async def fetch_and_process_hashtag(
        self,
        hashtag: str,
        limit: int = 20,
    ) -> List[Dict[str, Any]]:
        """Fetch and process posts for a hashtag.

        Args:
            hashtag: Hashtag to fetch (without #).
            limit: Maximum number of posts to fetch.

        Returns:
            List of processed post data.

        """
        raw_posts = await self.fetch_hashtag_timeline(hashtag, limit)
        processed_posts = []

        for raw_post in raw_posts:
            post_data = self.extract_post_data(raw_post)
            if post_data:  # Only include successfully processed posts
                processed_posts.append(post_data)

        logger.info(f"Processed {len(processed_posts)} posts for #{hashtag}")
        return processed_posts


async def test_fediverse_connection() -> bool:
    """Test connection to default Fediverse instance.

    Returns:
        True if connection successful, False otherwise.

    """
    client = None
    try:
        client = FediverseClient()
        # Try to fetch a common hashtag
        posts = await client.fetch_hashtag_timeline("test", limit=1)
        return len(posts) >= 0  # Even empty response means API is reachable
    except Exception as e:
        logger.error(f"Fediverse connection test failed: {e}")
        return False
    finally:
        if client:
            await client.close()
