"""TikTok API client implementation.

This module provides a concrete implementation of the SocialMediaPlatform
ABC for TikTok, using the TikTok for Business API (hypothetical).

API Documentation: https://developers.tiktok.com/doc/overview
"""

from datetime import datetime
from typing import Any

from pydantic import HttpUrl

from src.marqetive.platforms.base import SocialMediaPlatform
from src.marqetive.platforms.exceptions import (
    PlatformAuthError,
    PlatformError,
    PostNotFoundError,
    ValidationError,
)
from src.marqetive.platforms.models import (
    AuthCredentials,
    Comment,
    CommentStatus,
    MediaAttachment,
    MediaType,
    Post,
    PostCreateRequest,
    PostStatus,
    PostUpdateRequest,
)
from src.marqetive.platforms.tiktok.media import TikTokMediaManager


class TikTokClient(SocialMediaPlatform):
    """TikTok API client.

    This client implements the SocialMediaPlatform interface for TikTok,
    focusing on video uploads and management.
    """

    def __init__(
        self,
        credentials: AuthCredentials,
        timeout: float = 300.0,
    ) -> None:
        """Initialize TikTok client."""
        base_url = "https://open.tiktokapis.com/v2/"
        super().__init__(
            platform_name="tiktok",
            credentials=credentials,
            base_url=base_url,
            timeout=timeout,
        )
        self._media_manager: TikTokMediaManager | None = None

    async def _setup_managers(self) -> None:
        """Setup media manager."""
        if not self.credentials.access_token or not self.credentials.additional_data:
            raise PlatformAuthError("Access token and open_id are required", "tiktok")

        self._media_manager = TikTokMediaManager(
            access_token=self.credentials.access_token,
            open_id=self.credentials.additional_data["open_id"],
            timeout=self.timeout,
        )

    async def _cleanup_managers(self) -> None:
        """Cleanup media manager."""
        if self._media_manager:
            await self._media_manager.__aexit__(None, None, None)
            self._media_manager = None

    async def __aenter__(self) -> "TikTokClient":
        await super().__aenter__()
        await self._setup_managers()
        return self

    async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
        await self._cleanup_managers()
        await super().__aexit__(exc_type, exc_val, exc_tb)

    async def authenticate(self) -> AuthCredentials:
        """Perform TikTok authentication."""
        if await self.is_authenticated():
            return self.credentials
        raise PlatformAuthError(
            "Invalid or expired credentials. Please re-authenticate via TikTok OAuth.",
            platform=self.platform_name,
        )

    async def refresh_token(self) -> AuthCredentials:
        """Refresh TikTok access token."""
        # The refresh logic should be handled by the AccountFactory
        # For now, we assume it's done and we just return the creds
        return self.credentials

    async def is_authenticated(self) -> bool:
        """Check if TikTok credentials are valid."""
        if not self.api_client or not self.credentials.additional_data:
            return False
        try:
            # Verify credentials by fetching authenticated user info
            params = {
                "fields": "open_id,union_id,avatar_url,display_name",
                "open_id": self.credentials.additional_data["open_id"],
            }
            response = await self.api_client.get("user/info/", params=params)
            return response.data.get("data", {}).get("user") is not None
        except PlatformError:
            return False

    async def create_post(self, request: PostCreateRequest) -> Post:
        """Create and publish a TikTok video.

        Args:
            request: The post creation request, must contain a video URL.

        Returns:
            The created Post object.

        Raises:
            ValidationError: If the request is invalid (e.g., no media).
            MediaUploadError: If the video upload fails.
        """
        if not self._media_manager or not self.api_client:
            raise RuntimeError("Client must be used as async context manager")

        if not request.media_urls:
            raise ValidationError(
                "A video URL is required to create a TikTok post.",
                platform=self.platform_name,
            )

        # 1. Upload the video
        video_url = request.media_urls[0]
        upload_result = await self._media_manager.upload_media(video_url)

        if not upload_result.media_id:
            raise PlatformError("Media upload succeeded but did not yield a media ID.")

        # 2. Create the post with the uploaded video
        payload = {
            "post_info": {
                "title": request.content or "",
                "description": request.additional_data.get("description", ""),
                "privacy_level": request.additional_data.get(
                    "privacy_level", "PUBLIC_TO_EVERYONE"
                ),
            },
            "source_info": {
                "source": "FILE_UPLOAD",
                "video_id": upload_result.media_id,
            },
        }
        response = await self.api_client.post("video/publish/", data=payload)
        post_id = response.data.get("data", {}).get("publish_id")

        if not post_id:
            raise PlatformError("Post creation succeeded but no publish_id returned.")

        # 3. Fetch the created post to return a full Post object
        return await self.get_post(post_id)

    async def get_post(self, post_id: str) -> Post:
        """Retrieve a TikTok video by its ID."""
        if not self.api_client or not self.credentials.additional_data:
            raise RuntimeError("Client must be used as async context manager")
        try:
            params = {
                "open_id": self.credentials.additional_data["open_id"],
                "video_ids": [post_id],
            }
            response = await self.api_client.post("video/query/", data=params)
            video_data = response.data.get("data", {}).get("videos", [])
            if not video_data:
                raise PostNotFoundError(post_id, self.platform_name)
            return self._parse_video_post(video_data[0])
        except PlatformError as e:
            raise PostNotFoundError(
                post_id, self.platform_name, status_code=e.status_code
            ) from e

    async def update_post(self, post_id: str, request: PostUpdateRequest) -> Post:
        """Update a TikTok video. This is not supported by TikTok API."""
        raise PlatformError(
            "TikTok API does not support updating videos.", self.platform_name
        )

    async def delete_post(self, post_id: str) -> bool:
        """Delete a TikTok video. This is not supported by TikTok API."""
        raise PlatformError(
            "TikTok API does not support deleting videos.", self.platform_name
        )

    async def get_comments(
        self, post_id: str, limit: int = 20, offset: int = 0
    ) -> list[Comment]:
        """Retrieve comments for a TikTok video."""
        if not self.api_client or not self.credentials.additional_data:
            raise RuntimeError("Client must be used as async context manager")
        # This is a hypothetical endpoint
        params = {
            "open_id": self.credentials.additional_data["open_id"],
            "video_id": post_id,
            "count": limit,
            "cursor": offset,
        }
        response = await self.api_client.get("video/comment/list/", params=params)
        comments_data = response.data.get("data", {}).get("comments", [])
        return [self._parse_comment(c, post_id) for c in comments_data]

    async def create_comment(self, post_id: str, content: str) -> Comment:
        """Create a comment on a TikTok video."""
        raise PlatformError("Commenting via API is not supported.", self.platform_name)

    async def delete_comment(self, comment_id: str) -> bool:
        """Delete a comment on a TikTok video."""
        raise PlatformError(
            "Deleting comments via API is not supported.", self.platform_name
        )

    async def upload_media(
        self, media_url: str, media_type: str, alt_text: str | None = None
    ) -> MediaAttachment:
        """Upload a video to TikTok."""
        if not self._media_manager:
            raise RuntimeError("Client not initialized. Use as async context manager.")
        if media_type != "video":
            raise ValidationError("Only video media type is supported for TikTok.")

        result = await self._media_manager.upload_media(media_url)
        return MediaAttachment(
            media_id=result.media_id or result.upload_id,
            media_type=MediaType.VIDEO,
            url=HttpUrl(media_url),
        )

    def _parse_video_post(self, video_data: dict[str, Any]) -> Post:
        """Parse a TikTok API video object into a Post model."""
        return Post(
            post_id=video_data["video_id"],
            platform=self.platform_name,
            content=video_data.get("title", ""),
            media=[
                MediaAttachment(
                    media_id=video_data["video_id"],
                    media_type=MediaType.VIDEO,
                    url=HttpUrl(video_data.get("share_url", "")),
                    width=video_data.get("width"),
                    height=video_data.get("height"),
                )
            ],
            status=PostStatus.PUBLISHED,
            created_at=datetime.fromtimestamp(video_data.get("create_time", 0)),
            author_id=str(video_data.get("open_id")),
            likes_count=video_data.get("like_count", 0),
            comments_count=video_data.get("comment_count", 0),
            shares_count=video_data.get("share_count", 0),
            views_count=video_data.get("view_count", 0),
            raw_data=video_data,
        )

    def _parse_comment(self, comment_data: dict[str, Any], post_id: str) -> Comment:
        """Parse a TikTok API comment object into a Comment model."""
        return Comment(
            comment_id=comment_data["comment_id"],
            post_id=post_id,
            platform=self.platform_name,
            content=comment_data.get("text", ""),
            author_id=comment_data.get("open_id", ""),
            created_at=datetime.fromtimestamp(comment_data.get("create_time", 0)),
            likes_count=comment_data.get("like_count", 0),
            replies_count=0,
            status=CommentStatus.VISIBLE,
            raw_data=comment_data,
        )
