from __future__ import annotations

from typing import Any, Dict, List, Optional, TYPE_CHECKING

if TYPE_CHECKING:
    from socialrails.client import SocialRails, AsyncSocialRails


class Posts:
    """Synchronous resource for managing posts."""

    def __init__(self, client: SocialRails) -> None:
        self._client = client

    def create(
        self,
        *,
        content: str,
        platform: str,
        scheduled_for: Optional[str] = None,
        media: Optional[List[str]] = None,
        platform_settings: Optional[Dict[str, Any]] = None,
        thread: Optional[List[str]] = None,
        thread_media: Optional[Dict[str, List[str]]] = None,
        thread_delay: Optional[int] = None,
    ) -> Dict[str, Any]:
        """Create a new post.

        Args:
            content: The post text content (max 5000 characters).
            platform: Target platform (e.g. "twitter", "linkedin").
            scheduled_for: Optional ISO 8601 datetime to schedule the post.
            media: Optional list of media keys from the upload endpoint.
            platform_settings: Optional platform-specific settings.
            thread: Optional list of strings for threaded posts (twitter, threads).
            thread_media: Optional mapping of thread indices to media key arrays.
            thread_delay: Optional delay in minutes between thread items (0-60).

        Returns:
            The created post data.
        """
        body: Dict[str, Any] = {"content": content, "platform": platform}
        if scheduled_for is not None:
            body["scheduled_for"] = scheduled_for
        if media is not None:
            body["media"] = media
        if platform_settings is not None:
            body["platform_settings"] = platform_settings
        if thread is not None:
            body["thread"] = thread
        if thread_media is not None:
            body["thread_media"] = thread_media
        if thread_delay is not None:
            body["thread_delay"] = thread_delay
        return self._client._post("/posts", body)

    def list(
        self,
        *,
        status: Optional[str] = None,
        platform: Optional[str] = None,
        sort: Optional[str] = None,
        from_date: Optional[str] = None,
        to_date: Optional[str] = None,
        limit: Optional[int] = None,
        offset: Optional[int] = None,
    ) -> Dict[str, Any]:
        """List posts with optional filtering and pagination.

        Args:
            status: Filter by status (draft, scheduled, posted, failed).
            platform: Filter by platform.
            sort: Sort field (created_at or scheduled_for).
            from_date: Filter posts created on or after this ISO 8601 date.
            to_date: Filter posts created on or before this ISO 8601 date.
            limit: Maximum number of posts to return (1-100, default 50).
            offset: Number of posts to skip for pagination.

        Returns:
            Dict with "data" (list of posts) and "pagination" metadata.
        """
        params: Dict[str, Any] = {}
        if status is not None:
            params["status"] = status
        if platform is not None:
            params["platform"] = platform
        if sort is not None:
            params["sort"] = sort
        if from_date is not None:
            params["from"] = from_date
        if to_date is not None:
            params["to"] = to_date
        if limit is not None:
            params["limit"] = str(limit)
        if offset is not None:
            params["offset"] = str(offset)
        return self._client._get("/posts", params)

    def get(self, post_id: str) -> Dict[str, Any]:
        """Get a single post by ID.

        Args:
            post_id: The UUID of the post.

        Returns:
            The post data.
        """
        return self._client._get(f"/posts/{post_id}")

    def update(
        self,
        post_id: str,
        *,
        content: Optional[str] = None,
        platform: Optional[str] = None,
        scheduled_for: Optional[str] = None,
        media: Optional[List[str]] = None,
        platform_settings: Optional[Dict[str, Any]] = None,
    ) -> Dict[str, Any]:
        """Update a draft or scheduled post.

        Args:
            post_id: The UUID of the post to update.
            content: New post text content.
            platform: New target platform.
            scheduled_for: New scheduled datetime (ISO 8601), or None to unschedule.
            media: New list of media keys.
            platform_settings: New platform-specific settings.

        Returns:
            The updated post data.
        """
        body: Dict[str, Any] = {}
        if content is not None:
            body["content"] = content
        if platform is not None:
            body["platform"] = platform
        if scheduled_for is not None:
            body["scheduled_for"] = scheduled_for
        if media is not None:
            body["media"] = media
        if platform_settings is not None:
            body["platform_settings"] = platform_settings
        return self._client._patch(f"/posts/{post_id}", body)

    def delete(self, post_id: str) -> Dict[str, Any]:
        """Delete a draft or scheduled post.

        Args:
            post_id: The UUID of the post to delete.

        Returns:
            Dict with "id" and "deleted" confirmation.
        """
        return self._client._delete(f"/posts/{post_id}")

    def batch(
        self,
        *,
        content: str,
        platforms: List[str],
        scheduled_for: Optional[str] = None,
        platform_content: Optional[Dict[str, str]] = None,
        media: Optional[List[str]] = None,
        platform_settings: Optional[Dict[str, Dict[str, Any]]] = None,
    ) -> Dict[str, Any]:
        """Create posts across multiple platforms in a single batch.

        Args:
            content: Default post text content (max 5000 characters).
            platforms: List of target platforms (max 9).
            scheduled_for: Optional ISO 8601 datetime to schedule all posts.
            platform_content: Optional per-platform content overrides.
            media: Optional list of media keys shared across all platforms.
            platform_settings: Optional per-platform settings overrides.

        Returns:
            Dict with "batch_id" and "posts" list.
        """
        body: Dict[str, Any] = {"content": content, "platforms": platforms}
        if scheduled_for is not None:
            body["scheduled_for"] = scheduled_for
        if platform_content is not None:
            body["platform_content"] = platform_content
        if media is not None:
            body["media"] = media
        if platform_settings is not None:
            body["platform_settings"] = platform_settings
        return self._client._post("/posts/batch", body)


class AsyncPosts:
    """Asynchronous resource for managing posts."""

    def __init__(self, client: AsyncSocialRails) -> None:
        self._client = client

    async def create(
        self,
        *,
        content: str,
        platform: str,
        scheduled_for: Optional[str] = None,
        media: Optional[List[str]] = None,
        platform_settings: Optional[Dict[str, Any]] = None,
        thread: Optional[List[str]] = None,
        thread_media: Optional[Dict[str, List[str]]] = None,
        thread_delay: Optional[int] = None,
    ) -> Dict[str, Any]:
        """Create a new post.

        Args:
            content: The post text content (max 5000 characters).
            platform: Target platform (e.g. "twitter", "linkedin").
            scheduled_for: Optional ISO 8601 datetime to schedule the post.
            media: Optional list of media keys from the upload endpoint.
            platform_settings: Optional platform-specific settings.
            thread: Optional list of strings for threaded posts (twitter, threads).
            thread_media: Optional mapping of thread indices to media key arrays.
            thread_delay: Optional delay in minutes between thread items (0-60).

        Returns:
            The created post data.
        """
        body: Dict[str, Any] = {"content": content, "platform": platform}
        if scheduled_for is not None:
            body["scheduled_for"] = scheduled_for
        if media is not None:
            body["media"] = media
        if platform_settings is not None:
            body["platform_settings"] = platform_settings
        if thread is not None:
            body["thread"] = thread
        if thread_media is not None:
            body["thread_media"] = thread_media
        if thread_delay is not None:
            body["thread_delay"] = thread_delay
        return await self._client._post("/posts", body)

    async def list(
        self,
        *,
        status: Optional[str] = None,
        platform: Optional[str] = None,
        sort: Optional[str] = None,
        from_date: Optional[str] = None,
        to_date: Optional[str] = None,
        limit: Optional[int] = None,
        offset: Optional[int] = None,
    ) -> Dict[str, Any]:
        """List posts with optional filtering and pagination.

        Args:
            status: Filter by status (draft, scheduled, posted, failed).
            platform: Filter by platform.
            sort: Sort field (created_at or scheduled_for).
            from_date: Filter posts created on or after this ISO 8601 date.
            to_date: Filter posts created on or before this ISO 8601 date.
            limit: Maximum number of posts to return (1-100, default 50).
            offset: Number of posts to skip for pagination.

        Returns:
            Dict with "data" (list of posts) and "pagination" metadata.
        """
        params: Dict[str, Any] = {}
        if status is not None:
            params["status"] = status
        if platform is not None:
            params["platform"] = platform
        if sort is not None:
            params["sort"] = sort
        if from_date is not None:
            params["from"] = from_date
        if to_date is not None:
            params["to"] = to_date
        if limit is not None:
            params["limit"] = str(limit)
        if offset is not None:
            params["offset"] = str(offset)
        return await self._client._get("/posts", params)

    async def get(self, post_id: str) -> Dict[str, Any]:
        """Get a single post by ID.

        Args:
            post_id: The UUID of the post.

        Returns:
            The post data.
        """
        return await self._client._get(f"/posts/{post_id}")

    async def update(
        self,
        post_id: str,
        *,
        content: Optional[str] = None,
        platform: Optional[str] = None,
        scheduled_for: Optional[str] = None,
        media: Optional[List[str]] = None,
        platform_settings: Optional[Dict[str, Any]] = None,
    ) -> Dict[str, Any]:
        """Update a draft or scheduled post.

        Args:
            post_id: The UUID of the post to update.
            content: New post text content.
            platform: New target platform.
            scheduled_for: New scheduled datetime (ISO 8601), or None to unschedule.
            media: New list of media keys.
            platform_settings: New platform-specific settings.

        Returns:
            The updated post data.
        """
        body: Dict[str, Any] = {}
        if content is not None:
            body["content"] = content
        if platform is not None:
            body["platform"] = platform
        if scheduled_for is not None:
            body["scheduled_for"] = scheduled_for
        if media is not None:
            body["media"] = media
        if platform_settings is not None:
            body["platform_settings"] = platform_settings
        return await self._client._patch(f"/posts/{post_id}", body)

    async def delete(self, post_id: str) -> Dict[str, Any]:
        """Delete a draft or scheduled post.

        Args:
            post_id: The UUID of the post to delete.

        Returns:
            Dict with "id" and "deleted" confirmation.
        """
        return await self._client._delete(f"/posts/{post_id}")

    async def batch(
        self,
        *,
        content: str,
        platforms: List[str],
        scheduled_for: Optional[str] = None,
        platform_content: Optional[Dict[str, str]] = None,
        media: Optional[List[str]] = None,
        platform_settings: Optional[Dict[str, Dict[str, Any]]] = None,
    ) -> Dict[str, Any]:
        """Create posts across multiple platforms in a single batch.

        Args:
            content: Default post text content (max 5000 characters).
            platforms: List of target platforms (max 9).
            scheduled_for: Optional ISO 8601 datetime to schedule all posts.
            platform_content: Optional per-platform content overrides.
            media: Optional list of media keys shared across all platforms.
            platform_settings: Optional per-platform settings overrides.

        Returns:
            Dict with "batch_id" and "posts" list.
        """
        body: Dict[str, Any] = {"content": content, "platforms": platforms}
        if scheduled_for is not None:
            body["scheduled_for"] = scheduled_for
        if platform_content is not None:
            body["platform_content"] = platform_content
        if media is not None:
            body["media"] = media
        if platform_settings is not None:
            body["platform_settings"] = platform_settings
        return await self._client._post("/posts/batch", body)
