"""
ScrapeCreators API integration - FULL coverage.

Pay-as-you-go social media scraping API.
1 request = 1 credit (most endpoints).

Pricing:
- Free: 100 credits
- Starter: $10 / 5,000 credits
- Pro: $47 / 25,000 credits

Covers: TikTok, Instagram, YouTube, TikTok Shop

Docs: https://docs.scrapecreators.com/
"""

import re
import httpx
from datetime import datetime


class ScrapeCreatorsAPI:
    """ScrapeCreators API client for social media data."""

    BASE_URL = "https://api.scrapecreators.com"

    def __init__(self, api_key: str):
        if not api_key:
            raise ValueError(
                "ScrapeCreators API key required. "
                "Get one at https://scrapecreators.com (100 credits free)"
            )
        self.api_key = api_key
        self.headers = {
            "x-api-key": api_key,
            "Content-Type": "application/json",
        }

    def _request(self, endpoint: str, params: dict | None = None) -> dict:
        """Make an API request."""
        try:
            with httpx.Client(timeout=60) as client:
                resp = client.get(
                    f"{self.BASE_URL}{endpoint}",
                    params=params,
                    headers=self.headers,
                )
                resp.raise_for_status()
                return resp.json()
        except httpx.HTTPStatusError as e:
            if e.response.status_code == 401:
                raise ValueError("ScrapeCreators: API key invalida")
            if e.response.status_code == 429:
                raise ValueError("ScrapeCreators: Rate limit atingido")
            raise
        except Exception as e:
            print(f"[ScrapeCreators] Request error: {e}")
            return {}

    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    #  TikTok - Profile & Videos
    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    def tiktok_profile(self, username: str) -> dict:
        """Get TikTok user profile info. Cost: 1 credit."""
        data = self._request("/v1/tiktok/profile", {"handle": username})
        return data.get("user", data.get("data", {}))

    # Alias
    tiktok_user_info = tiktok_profile

    def tiktok_user_videos(
        self, username: str, count: int = 30, cursor: str = "", sort_by: str = ""
    ) -> list[dict]:
        """Get videos from a TikTok user. Cost: 1 credit per page.
        sort_by: 'popular' to sort by most popular."""
        params = {"handle": username, "count": min(count, 30)}
        if cursor:
            params["cursor"] = cursor
        if sort_by:
            params["sort_by"] = sort_by
        data = self._request("/v1/tiktok/profile/videos", params)
        aweme_list = data.get("aweme_list")
        if aweme_list is not None:
            # v2 aweme format
            return [self._parse_aweme(v) for v in (aweme_list or []) if v]
        items = data.get("data", {}).get("videos", []) or data.get("itemList", [])
        return [self._parse_tiktok_video(v) for v in (items or []) if v]

    def tiktok_video_info(self, url: str) -> dict:
        """Get info for a specific TikTok video. Cost: 1 credit.
        Returns video data including shop_product_url if product is promoted."""
        data = self._request("/v2/tiktok/video", {"url": url})
        detail = data.get("aweme_detail", {})
        if detail:
            return self._parse_aweme(detail)
        # Fallback to v1
        data = self._request("/v1/tiktok/video", {"url": url})
        item_info = data.get("itemInfo", {}).get("itemStruct", {})
        if item_info:
            parsed = self._parse_tiktok_video(item_info)
            parsed["transcript"] = data.get("transcript")
            return parsed
        return {}

    def tiktok_video_transcript(self, url: str, use_ai_fallback: bool = True) -> dict:
        """Get transcript of a TikTok video. Cost: 1 credit."""
        params = {"url": url}
        if use_ai_fallback:
            params["use_ai_as_fallback"] = "true"
        data = self._request("/v1/tiktok/video/transcript", params)
        return {
            "transcript": data.get("transcript"),
            "url": data.get("url", url),
        }

    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    #  TikTok - Search
    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    def tiktok_search(self, query: str, count: int = 30) -> list[dict]:
        """Search TikTok videos by keyword. Cost: 1 credit."""
        params = {"query": query, "count": min(count, 30)}
        data = self._request("/v1/tiktok/search/keyword", params)
        items = data.get("search_item_list") or data.get("aweme_list") or []
        return [self._parse_tiktok_search_item(v) for v in items if v]

    def tiktok_search_top(self, query: str, count: int = 30) -> list[dict]:
        """Top search: videos + photo carousels. Cost: 1 credit.
        Returns items with shop_product_url when creators promote products."""
        params = {"query": query, "count": min(count, 30)}
        data = self._request("/v1/tiktok/search/top", params)
        items = data.get("items") or []
        return [self._parse_tiktok_search_top_item(v) for v in items if v]

    def tiktok_search_users(self, query: str, count: int = 30) -> list[dict]:
        """Search TikTok users. Cost: 1 credit."""
        params = {"query": query, "count": min(count, 30)}
        data = self._request("/v1/tiktok/search/users", params)
        return data.get("challenge_list") or data.get("user_list") or []

    def tiktok_hashtag_videos(self, hashtag: str, count: int = 30, cursor: str = "") -> list[dict]:
        """Get videos for a TikTok hashtag. Cost: 1 credit."""
        params = {"hashtag": hashtag.strip("#"), "count": min(count, 30)}
        if cursor:
            params["cursor"] = cursor
        data = self._request("/v1/tiktok/search/hashtag", params)
        items = data.get("aweme_list") or []
        return [self._parse_aweme(v) for v in items if v]

    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    #  TikTok - Social (Comments, Followers, Following, Live)
    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    def tiktok_comments(self, url: str, count: int = 30, cursor: str = "") -> dict:
        """Get comments from a TikTok video. Cost: 1 credit."""
        params = {"url": url, "count": min(count, 30)}
        if cursor:
            params["cursor"] = cursor
        data = self._request("/v1/tiktok/video/comments", params)
        return {
            "comments": data.get("comments", []),
            "has_more": data.get("has_more", False),
            "cursor": data.get("cursor", ""),
        }

    def tiktok_followers(self, username: str, count: int = 30, cursor: str = "") -> dict:
        """Get followers of a TikTok user. Cost: 1 credit."""
        params = {"handle": username, "count": min(count, 30)}
        if cursor:
            params["cursor"] = cursor
        data = self._request("/v1/tiktok/user/followers", params)
        return {
            "followers": data.get("followers", []),
            "has_more": data.get("has_more", False),
            "cursor": data.get("cursor", ""),
        }

    def tiktok_following(self, username: str, count: int = 30, cursor: str = "") -> dict:
        """Get accounts a TikTok user follows. Cost: 1 credit."""
        params = {"handle": username, "count": min(count, 30)}
        if cursor:
            params["cursor"] = cursor
        data = self._request("/v1/tiktok/user/following", params)
        return {
            "following": data.get("following", []),
            "has_more": data.get("has_more", False),
        }

    def tiktok_live(self, username: str) -> dict:
        """Get live stream data for a TikTok user. Cost: 1 credit."""
        data = self._request("/v1/tiktok/user/live", {"handle": username})
        return data.get("liveRoomUserInfo", data.get("data", {}))

    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    #  TikTok - Songs
    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    def tiktok_song_details(self, url: str) -> dict:
        """Get details of a TikTok song/sound. Cost: 1 credit."""
        data = self._request("/v1/tiktok/song", {"url": url})
        return data.get("data", data)

    def tiktok_song_videos(self, url: str, count: int = 30) -> list[dict]:
        """Get TikTok videos using a specific song. Cost: 1 credit."""
        params = {"url": url, "count": min(count, 30)}
        data = self._request("/v1/tiktok/song/videos", params)
        items = data.get("aweme_list") or data.get("videos") or []
        return [self._parse_aweme(v) if v.get("aweme_id") else self._parse_tiktok_video(v) for v in items if v]

    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    #  TikTok Shop
    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    def tiktok_shop_search(self, query: str, amount: int = 30) -> list[dict]:
        """Search TikTok Shop products. Cost: 1 credit."""
        params = {"query": query, "amount": min(amount, 500)}
        data = self._request("/v1/tiktok/shop/search", params)
        products = data.get("products") or []
        return [self._parse_shop_product(p) for p in products if p]

    def tiktok_shop_product(self, url: str, get_related_videos: bool = True) -> dict:
        """Get TikTok Shop product details. Cost: 1 credit."""
        params = {"url": url}
        if get_related_videos:
            params["get_related_videos"] = "true"
        data = self._request("/v1/tiktok/product", params)
        return self._parse_shop_product_details(data)

    def tiktok_shop_products(self, store_url: str, cursor: str = "") -> dict:
        """Get all products from a TikTok Shop store. Cost: 1 credit."""
        params = {"url": store_url}
        if cursor:
            params["cursor"] = cursor
        data = self._request("/v1/tiktok/shop/products", params)
        shop_info = data.get("shopInfo") or {}
        products = data.get("products") or []
        return {
            "shop_info": {
                "seller_id": shop_info.get("seller_id", ""),
                "shop_name": shop_info.get("shop_name", ""),
                "shop_link": shop_info.get("shop_link", ""),
                "shop_logo": shop_info.get("shop_logo", ""),
                "shop_rating": shop_info.get("shop_rating", 0),
                "sold_count": shop_info.get("sold_count", 0),
                "format_sold_count": shop_info.get("format_sold_count", ""),
                "followers_count": shop_info.get("followers_count", 0),
                "format_followers_count": shop_info.get("format_followers_count", ""),
                "review_count": shop_info.get("review_count", 0),
                "video_count": shop_info.get("video_count", 0),
                "on_sell_product_count": shop_info.get("on_sell_product_count", 0),
                "region": shop_info.get("region", ""),
                "shop_slogan": shop_info.get("shop_slogan", ""),
                "creator_name": shop_info.get("creator_name", ""),
            },
            "products": [self._parse_shop_product(p) for p in products if p],
            "has_more": data.get("has_more", False),
            "cursor": data.get("cursor", ""),
        }

    def tiktok_shop_reviews(self, product_url: str, count: int = 30, cursor: str = "") -> dict:
        """Get reviews for a TikTok Shop product. Cost: 1 credit."""
        params = {"url": product_url, "count": min(count, 30)}
        if cursor:
            params["cursor"] = cursor
        data = self._request("/v1/tiktok/shop/product/reviews", params)
        return data.get("data", data)

    def _parse_shop_product(self, item: dict) -> dict:
        """Parse a TikTok Shop product into standard format."""
        price_info = item.get("product_price_info", {}) or {}
        sold_info = item.get("sold_info", {}) or {}
        seller_info = item.get("seller_info", {}) or {}
        rate_info = item.get("rate_info", {}) or {}

        # Image handling - multiple fallback sources
        image = item.get("image", "") or item.get("cover", "") or item.get("thumbnail", "")
        if isinstance(image, dict):
            url_list = image.get("url_list") or image.get("thumb_url_list") or []
            image = url_list[0] if url_list else (image.get("url", "") or image.get("uri", ""))
        # Try images array if still empty
        if not image:
            images = item.get("images", [])
            if images and isinstance(images[0], dict):
                urls = images[0].get("url_list") or images[0].get("thumb_url_list") or []
                image = urls[0] if urls else ""

        # Sold count
        sold_count = 0
        sold_str = sold_info.get("sold_count", "") or sold_info.get("text", "")
        if isinstance(sold_str, int):
            sold_count = sold_str
        elif isinstance(sold_str, str):
            sold_str = sold_str.replace(",", "").replace("+", "").strip()
            nums = re.findall(r"[\d.]+[KkMm]?", sold_str)
            if nums:
                val = nums[0]
                if val[-1] in "Kk":
                    sold_count = int(float(val[:-1]) * 1000)
                elif val[-1] in "Mm":
                    sold_count = int(float(val[:-1]) * 1000000)
                else:
                    try:
                        sold_count = int(float(val))
                    except ValueError:
                        pass

        # Price
        price = ""
        if isinstance(price_info, dict):
            # Try formatted price first, then raw price
            sale_fmt = price_info.get("sale_price_format", "")
            symbol = price_info.get("currency_symbol", "$")
            if sale_fmt:
                price = f"{symbol}{sale_fmt}" if symbol and not sale_fmt.startswith(symbol) else sale_fmt
            else:
                price = price_info.get("price", "") or price_info.get("sale_price", "")
        elif isinstance(price_info, str):
            price = price_info

        # URL handling (can be string or dict with canonical_url)
        raw_url = item.get("seo_url", "") or item.get("url", "")
        if isinstance(raw_url, dict):
            raw_url = raw_url.get("canonical_url", "") or raw_url.get("url", "")
        pid = str(item.get("product_id", "") or item.get("id", ""))
        if not raw_url and pid:
            raw_url = f"https://www.tiktok.com/shop/pdp/{pid}"

        return {
            "product_id": pid,
            "title": item.get("title", ""),
            "image": image,
            "price": price,
            "original_price": self._format_price(price_info, "origin_price_format", "origin_price"),
            "discount": price_info.get("discount_format", "") if isinstance(price_info, dict) else "",
            "sold_count": sold_count,
            "rating": float(rate_info.get("score", 0) or 0) if isinstance(rate_info, dict) else 0,
            "review_count": int(rate_info.get("review_count", 0) or 0) if isinstance(rate_info, dict) else 0,
            "seller_name": (seller_info.get("name", "") or seller_info.get("shop_name", "")) if isinstance(seller_info, dict) else "",
            "url": raw_url,
        }

    @staticmethod
    def _format_price(price_info, fmt_key: str, raw_key: str) -> str:
        if not isinstance(price_info, dict):
            return ""
        fmt = price_info.get(fmt_key, "")
        if fmt:
            symbol = price_info.get("currency_symbol", "$")
            return f"{symbol}{fmt}" if symbol and not str(fmt).startswith(symbol) else str(fmt)
        return str(price_info.get(raw_key, ""))

    def _parse_shop_product_details(self, data: dict) -> dict:
        """Parse detailed product response from /v1/tiktok/product.

        Real API structure:
        - product_base: {title, images, sold_count, price: {real_price, currency_symbol, min_sku_price}, category_name}
        - seller: {seller_id, name, avatar, product_count, rating, link, shop_link}
        - skus: [{sku_id, stock, price, ...}]
        - product_detail_review: {product_rating, review_count}
        - related_videos: [{item_id, play_count, like_count, author_name, title, url, cover_image_url}]
        """
        product_base = data.get("product_base", {}) or {}
        seller = data.get("seller", {}) or {}
        review_info = data.get("product_detail_review", {}) or {}
        related_videos = data.get("related_videos") or []
        skus = data.get("skus") or []

        # Price
        price_info = product_base.get("price", {}) or {}
        if isinstance(price_info, dict):
            real_price = price_info.get("real_price", "")
            symbol = price_info.get("currency_symbol", "$")
            min_price = price_info.get("min_sku_price", "")
            if real_price:
                price = real_price if symbol in str(real_price) else f"{symbol}{real_price}"
            elif min_price:
                price = f"{symbol}{min_price}"
            else:
                price = ""
            original_price = price_info.get("original_price", "")
        else:
            price = str(price_info)
            original_price = ""

        # Stock from SKUs
        total_stock = sum(int(s.get("stock", 0) or 0) for s in skus)

        # Images
        images = product_base.get("images", [])
        first_image = ""
        if images and isinstance(images[0], dict):
            urls = images[0].get("thumb_url_list") or images[0].get("url_list") or []
            first_image = urls[0] if urls else ""

        # Sold count
        sold_count = int(product_base.get("sold_count", 0) or 0)

        return {
            "product_id": str(data.get("product_id", "")),
            "title": product_base.get("title", ""),
            "description": "",  # Not in this endpoint
            "image": first_image,
            "images": images,
            "price": price,
            "original_price": original_price,
            "sold_count": sold_count,
            "stock": total_stock,
            "category": product_base.get("category_name", ""),
            "rating": float(review_info.get("product_rating", 0) or 0),
            "review_count": int(review_info.get("review_count", 0) or 0),
            "url": f"https://www.tiktok.com/shop/pdp/{data.get('product_id', '')}",
            "shop": {
                "name": seller.get("name", ""),
                "seller_id": seller.get("seller_id", ""),
                "url": seller.get("shop_link", "") or seller.get("link", ""),
                "rating": float(seller.get("rating", 0) or 0),
                "product_count": int(seller.get("product_count", 0) or 0),
            },
            "seller_name": seller.get("name", ""),
            "related_videos": [
                {
                    "url": v.get("url", ""),
                    "views": int(v.get("play_count", 0) or 0),
                    "likes": int(v.get("like_count", 0) or 0),
                    "author": v.get("author_name", ""),
                    "description": v.get("title", ""),
                    "thumbnail": v.get("cover_image_url", ""),
                }
                for v in related_videos
            ],
            "related_video_count": len(related_videos),
        }

    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    #  TikTok Video Parsers
    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    @staticmethod
    def _extract_tiktok_metadata(item: dict, author: dict = None, music_info: dict = None) -> dict:
        """Extract TikTok metadata fields common to all parsers."""
        author = author or item.get("author", {}) or {}
        music_info = music_info or item.get("music", {}) or {}
        aigc = item.get("aigc_info", {}) or {}
        cla = item.get("cla_info", {}) or {}
        orig_lang = cla.get("original_language_info", {}) or {}

        return {
            "region": str(item.get("region", "") or ""),
            "is_ad": bool(item.get("is_ad", False)),
            "is_paid_partnership": bool(item.get("is_paid_partnership", False)),
            "is_eligible_for_commission": bool(item.get("is_eligible_for_commission", False)),
            "with_shop_entry": bool(author.get("with_shop_entry", False)),
            "is_commerce_music": bool(music_info.get("is_commerce_music", False)),
            "created_by_ai": bool(aigc.get("created_by_ai", False)),
            "audio_language": str(orig_lang.get("lang", "") or orig_lang.get("language_code", "") or
                                  item.get("desc_language", "") or ""),
        }

    @staticmethod
    def _normalize_duration(d: int) -> int:
        """Normalize duration to seconds (API sometimes returns milliseconds)."""
        if d > 3600:
            return d // 1000
        return d

    @staticmethod
    def _parse_create_time(ts) -> datetime | None:
        """Parse create_time which can be int timestamp or ISO string."""
        if not ts:
            return None
        # Try as integer timestamp first
        if isinstance(ts, (int, float)):
            try:
                return datetime.fromtimestamp(int(ts))
            except (ValueError, TypeError, OSError):
                return None
        # Try as ISO string (e.g. "2026-02-12T14:08:33.000Z")
        if isinstance(ts, str):
            try:
                return datetime.fromisoformat(ts.replace("Z", "+00:00")).replace(tzinfo=None)
            except (ValueError, AttributeError):
                pass
            try:
                return datetime.fromtimestamp(int(ts))
            except (ValueError, TypeError, OSError):
                pass
        return None

    def _parse_aweme(self, item: dict) -> dict:
        """Parse aweme_detail / aweme_list item format (v2 API)."""
        stats = item.get("statistics", {}) or {}
        author = item.get("author", {}) or {}
        video = item.get("video", {}) or {}

        published_at = self._parse_create_time(item.get("create_time"))

        desc = item.get("desc", "") or ""
        hashtags = re.findall(r"#(\w+)", desc)

        uid = author.get("unique_id", "") or author.get("uniqueId", "")
        aweme_id = str(item.get("aweme_id", "") or item.get("id", ""))

        followers = int(
            author.get("follower_count", 0)
            or author.get("followerCount", 0)
            or author.get("fans", 0)
            or 0
        )

        music_info = item.get("music", {}) or {}

        # Detect shop product
        shop_url = item.get("shop_product_url") or ""
        if not shop_url:
            has_shop_hashtag = any(h.lower() in ("tiktokshop", "tiktokmademebuyit", "tiktokfinds")
                                  for h in hashtags)
            is_commission = bool(item.get("is_eligible_for_commission"))
            if has_shop_hashtag or is_commission:
                shop_url = "tiktokshop_detected"

        return {
            "platform": "tiktok",
            "external_id": aweme_id,
            "url": f"https://www.tiktok.com/@{uid}/video/{aweme_id}",
            "title": desc[:200],
            "description": desc[:500],
            "hashtags": hashtags[:20],
            "creator_username": uid,
            "creator_display_name": author.get("nickname", ""),
            "creator_followers": followers,
            "views": int(stats.get("play_count", 0) or stats.get("playCount", 0) or 0),
            "likes": int(stats.get("digg_count", 0) or stats.get("diggCount", 0) or 0),
            "comments": int(stats.get("comment_count", 0) or stats.get("commentCount", 0) or 0),
            "shares": int(stats.get("share_count", 0) or stats.get("shareCount", 0) or 0),
            "duration": self._normalize_duration(int(video.get("duration", 0) or item.get("duration", 0) or 0)),
            "thumbnail_url": video.get("cover", {}).get("url_list", [""])[0]
            if isinstance(video.get("cover"), dict) else video.get("cover", ""),
            "published_at": published_at,
            "shop_product_url": shop_url,
            **self._extract_tiktok_metadata(item, author, music_info),
            "music": {
                "id": str(music_info.get("id", "") or music_info.get("mid", "") or ""),
                "title": music_info.get("title", "") or music_info.get("musicName", ""),
                "author": music_info.get("authorName", "") or music_info.get("author", ""),
                "url": music_info.get("playUrl", "") or music_info.get("play_url", ""),
                "duration": int(music_info.get("duration", 0) or 0),
                "album": music_info.get("album", ""),
            } if music_info.get("id") or music_info.get("mid") else None,
        }

    def _parse_tiktok_video(self, item: dict) -> dict:
        """Parse v1 TikTok video (itemStruct format)."""
        stats = item.get("stats", {}) or {}
        author = item.get("author", {}) or {}
        author_stats = item.get("authorStats", {}) or {}
        published_at = self._parse_create_time(item.get("createTime") or item.get("create_time"))

        desc = item.get("desc", "") or ""
        hashtags = re.findall(r"#(\w+)", desc)

        followers = int(
            author_stats.get("followerCount", 0)
            or author.get("follower_count", 0)
            or author.get("followerCount", 0)
            or author.get("fans", 0)
            or 0
        )

        music_info = item.get("music", {}) or {}

        # Detect shop product
        shop_url = item.get("shop_product_url") or ""
        if not shop_url:
            has_shop_hashtag = any(h.lower() in ("tiktokshop", "tiktokmademebuyit", "tiktokfinds")
                                  for h in hashtags)
            is_commission = bool(item.get("is_eligible_for_commission"))
            if has_shop_hashtag or is_commission:
                shop_url = "tiktokshop_detected"

        return {
            "platform": "tiktok",
            "external_id": str(item.get("id", "")),
            "url": f"https://www.tiktok.com/@{author.get('uniqueId', '')}/video/{item.get('id', '')}",
            "title": desc[:200],
            "description": desc[:500],
            "hashtags": hashtags[:20],
            "creator_username": author.get("uniqueId", ""),
            "creator_display_name": author.get("nickname", ""),
            "creator_followers": followers,
            "views": int(stats.get("playCount", 0) or 0),
            "likes": int(stats.get("diggCount", 0) or stats.get("likeCount", 0) or 0),
            "comments": int(stats.get("commentCount", 0) or 0),
            "shares": int(stats.get("shareCount", 0) or 0),
            "duration": int(item.get("video", {}).get("duration", 0) or 0),
            "thumbnail_url": item.get("video", {}).get("cover", ""),
            "published_at": published_at,
            "shop_product_url": shop_url,
            **self._extract_tiktok_metadata(item, author, music_info),
            "music": {
                "id": str(music_info.get("id", "") or music_info.get("mid", "") or ""),
                "title": music_info.get("title", "") or music_info.get("musicName", ""),
                "author": music_info.get("authorName", "") or music_info.get("author", ""),
                "url": music_info.get("playUrl", "") or music_info.get("play_url", ""),
                "duration": int(music_info.get("duration", 0) or 0),
                "album": music_info.get("album", ""),
            } if music_info.get("id") or music_info.get("mid") else None,
        }

    def _parse_tiktok_search_item(self, item: dict) -> dict:
        """Parse search/keyword result item."""
        # search_item_list items have 'aweme_info' nested
        aweme = item.get("aweme_info", item)
        if aweme.get("aweme_id") or aweme.get("statistics"):
            return self._parse_aweme(aweme)
        return self._parse_tiktok_video(aweme)

    def _parse_tiktok_search_top_item(self, item: dict) -> dict:
        """Parse search/top result item."""
        stats = item.get("statistics", {}) or {}
        author = item.get("author", {}) or {}
        video = item.get("video", {}) or {}

        published_at = self._parse_create_time(item.get("create_time"))

        desc = item.get("desc", "") or ""
        hashtags = re.findall(r"#(\w+)", desc)
        uid = author.get("unique_id", "") or author.get("uniqueId", "")
        vid_id = str(item.get("id", ""))

        followers = int(
            author.get("follower_count", 0)
            or author.get("followerCount", 0)
            or author.get("fans", 0)
            or 0
        )

        music_info = item.get("music", {}) or item.get("music_info", {}) or {}

        # Detect shop product: explicit URL, commission flag, or shop hashtags
        shop_url = item.get("shop_product_url") or ""
        if not shop_url:
            # Check for shop signals
            has_shop_hashtag = any(h.lower() in ("tiktokshop", "tiktokmademebuyit", "tiktokfinds")
                                  for h in hashtags)
            has_shop_entry = bool(author.get("with_shop_entry"))
            is_commission = bool(item.get("is_eligible_for_commission"))
            if has_shop_hashtag or is_commission:
                shop_url = "tiktokshop_detected"

        return {
            "platform": "tiktok",
            "external_id": vid_id,
            "url": item.get("url", f"https://www.tiktok.com/@{uid}/video/{vid_id}"),
            "title": desc[:200],
            "description": desc[:500],
            "hashtags": hashtags[:20],
            "creator_username": uid,
            "creator_display_name": author.get("nickname", ""),
            "creator_followers": followers,
            "views": int(stats.get("play_count", 0) or stats.get("playCount", 0) or 0),
            "likes": int(stats.get("digg_count", 0) or stats.get("diggCount", 0) or 0),
            "comments": int(stats.get("comment_count", 0) or stats.get("commentCount", 0) or 0),
            "shares": int(stats.get("share_count", 0) or stats.get("shareCount", 0) or 0),
            "duration": int(video.get("duration", 0) or 0),
            "thumbnail_url": video.get("cover", {}).get("url_list", [""])[0]
            if isinstance(video.get("cover"), dict) else video.get("cover", ""),
            "published_at": published_at,
            "content_type": item.get("content_type", "video"),
            "shop_product_url": shop_url,
            **self._extract_tiktok_metadata(item, author, music_info),
            "music": {
                "id": str(music_info.get("id", "") or music_info.get("mid", "") or ""),
                "title": music_info.get("title", "") or music_info.get("musicName", ""),
                "author": music_info.get("authorName", "") or music_info.get("author", ""),
                "url": music_info.get("playUrl", "") or music_info.get("play_url", ""),
                "duration": int(music_info.get("duration", 0) or 0),
                "album": music_info.get("album", ""),
            } if music_info.get("id") or music_info.get("mid") else None,
        }

    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    #  TikTok & YouTube - Trending Feeds
    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    def tiktok_trending_feed(self, region: str = "BR", count: int = 30) -> list[dict]:
        """Get TikTok trending/popular videos. Cost: 1 credit.
        Tries /v1/tiktok/trending first, falls back to search/top."""
        try:
            params = {"region": region, "count": min(count, 30)}
            data = self._request("/v1/tiktok/trending", params)
            items = (data.get("aweme_list") or data.get("items")
                     or data.get("item_list") or data.get("data") or [])
            if items:
                result = []
                for v in items:
                    if v.get("aweme_id") or v.get("statistics"):
                        result.append(self._parse_aweme(v))
                    elif v.get("id"):
                        result.append(self._parse_tiktok_video(v))
                return result
        except Exception:
            pass
        # Fallback to search/top with trending query
        return self.tiktok_search_top("trending viral", count)

    def youtube_shorts_feed(self, region: str = "BR", count: int = 30) -> list[dict]:
        """Get YouTube Shorts trending. Cost: 1 credit.
        Tries /v1/youtube/shorts first, falls back to search."""
        try:
            params = {"region": region, "count": min(count, 30)}
            data = self._request("/v1/youtube/shorts", params)
            items = data.get("shorts") or data.get("videos") or data.get("items") or []
            if items:
                return [self._parse_youtube_video(v) for v in items if v]
        except Exception:
            pass
        # Fallback to search with shorts filter
        result = self.youtube_search("trending shorts viral", count)
        return result.get("shorts", []) or result.get("videos", [])

    # Backwards compatibility aliases
    def tiktok_trending(self, region: str = "BR", count: int = 30) -> list[dict]:
        """Get trending TikTok content via search. Cost: 1 credit."""
        return self.tiktok_trending_feed(region, count)

    def tiktok_popular_videos(self, country: str = "BR", period: str = "7", count: int = 30) -> list[dict]:
        """Get popular TikTok videos. Uses search/top as fallback."""
        return self.tiktok_search_top("viral", count)

    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    #  Instagram
    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    def instagram_user_info(self, username: str) -> dict:
        """Get Instagram user profile info. Cost: 1 credit."""
        data = self._request("/v1/instagram/profile", {"handle": username})
        return data.get("data", data)

    def instagram_user_reels(self, username: str, count: int = 30) -> list[dict]:
        """Get reels from an Instagram user. Cost: 1 credit."""
        params = {"handle": username, "count": min(count, 30)}
        data = self._request("/v1/instagram/user/reels", params)
        items = data.get("items") or []
        return [self._parse_instagram_item(v) for v in items if v]

    def instagram_user_posts(self, username: str, count: int = 30) -> list[dict]:
        """Get posts from an Instagram user. Cost: 1 credit."""
        params = {"handle": username, "count": min(count, 30)}
        data = self._request("/v1/instagram/user/posts", params)
        items = data.get("posts") or []
        return [self._parse_instagram_item(v) for v in items if v]

    def instagram_hashtag(self, hashtag: str, count: int = 30) -> list[dict]:
        """Get posts for an Instagram hashtag. Cost: 1 credit."""
        # Use reels search as fallback since hashtag endpoint is not available
        return self.instagram_reels_search(hashtag.strip("#"), count)

    def instagram_explore(self, count: int = 30) -> list[dict]:
        """Get Instagram trending content. Cost: 1 credit."""
        # Use reels search as explore endpoint is not available
        return self.instagram_reels_search("trending viral", count)

    def instagram_reels_search(self, query: str, count: int = 30) -> list[dict]:
        """Search Instagram reels. Cost: 1 credit per 10 reels, max 60."""
        params = {"query": query, "count": min(count, 60)}
        data = self._request("/v1/instagram/reels/search", params)
        items = data.get("reels") or data.get("items") or []
        return [self._parse_instagram_reel_search(v) for v in items if v]

    def instagram_highlights(self, username: str) -> list[dict]:
        """Get Instagram story highlights. Cost: 1 credit."""
        data = self._request("/v1/instagram/user/highlights", {"handle": username})
        return data.get("highlights") or []

    def instagram_transcript(self, url: str) -> dict:
        """Get transcript of an Instagram video/reel. Cost: 1 credit."""
        data = self._request("/v2/instagram/media/transcript", {"url": url})
        return data.get("data", data)

    def _parse_instagram_item(self, item: dict) -> dict:
        """Parse Instagram post/reel item."""
        caption = item.get("caption", {}) or {}
        text = caption.get("text", "") if isinstance(caption, dict) else str(caption or "")
        hashtags = re.findall(r"#(\w+)", text)
        user = item.get("user", {}) or item.get("owner", {}) or {}

        published_at = None
        ts = item.get("taken_at")
        if ts:
            try:
                published_at = datetime.fromtimestamp(int(ts))
            except (ValueError, TypeError, OSError):
                pass

        return {
            "platform": "instagram",
            "external_id": str(item.get("pk", "") or item.get("id", "")),
            "url": f"https://www.instagram.com/reel/{item.get('code', item.get('shortcode', ''))}/",
            "title": text[:200],
            "description": text[:500],
            "hashtags": hashtags[:20],
            "creator_username": user.get("username", ""),
            "creator_display_name": user.get("full_name", ""),
            "creator_followers": int(user.get("follower_count", 0) or user.get("followerCount", 0) or 0),
            "views": int(item.get("play_count", 0) or item.get("view_count", 0) or item.get("video_play_count", 0) or 0),
            "likes": int(item.get("like_count", 0) or 0),
            "comments": int(item.get("comment_count", 0) or 0),
            "shares": int(item.get("share_count", 0) or 0),
            "duration": int(item.get("video_duration", 0) or 0),
            "thumbnail_url": item.get("image_versions2", {}).get("candidates", [{}])[0].get("url", "")
            if item.get("image_versions2") else item.get("thumbnail_src", ""),
            "published_at": published_at,
        }

    def _parse_instagram_reel_search(self, item: dict) -> dict:
        """Parse Instagram reels/search result item."""
        caption = item.get("caption", "") or ""
        if isinstance(caption, dict):
            caption = caption.get("text", "")
        hashtags = re.findall(r"#(\w+)", str(caption))

        return {
            "platform": "instagram",
            "external_id": str(item.get("id", "")),
            "url": item.get("url", f"https://www.instagram.com/reel/{item.get('shortcode', '')}/"),
            "title": str(caption)[:200],
            "description": str(caption)[:500],
            "hashtags": hashtags[:20],
            "creator_username": "",
            "creator_display_name": "",
            "views": int(item.get("video_view_count", 0) or item.get("video_play_count", 0) or 0),
            "likes": int(item.get("like_count", 0) or 0),
            "comments": int(item.get("comment_count", 0) or 0),
            "shares": 0,
            "duration": int(item.get("video_duration", 0) or 0),
            "thumbnail_url": item.get("thumbnail_src", "") or item.get("display_url", ""),
            "published_at": None,
        }

    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    #  YouTube
    # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    def youtube_trending(self, region: str = "BR", count: int = 30) -> list[dict]:
        """Get YouTube trending via search. Cost: 1 credit."""
        return self.youtube_search("trending viral", count).get("videos", [])

    def youtube_search(
        self, query: str, count: int = 30, sort_by: str = "", include_extras: bool = True
    ) -> dict:
        """Search YouTube. Cost: 1 credit.
        Returns separate arrays for videos, shorts, and lives."""
        params = {"query": query, "count": min(count, 30)}
        if sort_by:
            params["sortBy"] = sort_by
        if include_extras:
            params["includeExtras"] = "true"
        data = self._request("/v1/youtube/search", params)
        return {
            "videos": [self._parse_youtube_video(v) for v in (data.get("videos") or []) if v],
            "shorts": [self._parse_youtube_video(v) for v in (data.get("shorts") or []) if v],
            "lives": data.get("lives") or [],
        }

    def youtube_video_info(self, url: str) -> dict:
        """Get info for a specific YouTube video. Cost: 1 credit."""
        data = self._request("/v1/youtube/video", {"url": url})
        if data.get("id"):
            return self._parse_youtube_video(data)
        return {}

    def youtube_video_transcript(self, url: str) -> dict:
        """Get transcript of a YouTube video. Cost: 1 credit."""
        data = self._request("/v1/youtube/video/transcript", {"url": url})
        return {
            "transcript": data.get("transcript"),
            "transcript_text": data.get("transcript_only_text", ""),
            "language": data.get("language", ""),
            "url": data.get("url", url),
        }

    def youtube_channel_info(self, url: str) -> dict:
        """Get YouTube channel info. Cost: 1 credit."""
        data = self._request("/v1/youtube/channel", {"url": url})
        return data

    def youtube_channel_videos(
        self, url: str, count: int = 30, include_extras: bool = False
    ) -> dict:
        """Get videos from a YouTube channel. Cost: 1 credit.
        Returns videos, shorts, etc."""
        handle = url
        if "youtube.com" in url:
            if "@" in url:
                handle = "@" + url.split("@")[-1].split("/")[0].split("?")[0]
            elif "/channel/" in url:
                handle = url.split("/channel/")[-1].split("/")[0]
            elif "/c/" in url:
                handle = url.split("/c/")[-1].split("/")[0]
        if not handle.startswith("@"):
            handle = "@" + handle
        params = {"handle": handle, "count": min(count, 30)}
        if include_extras:
            params["includeExtras"] = "true"
        data = self._request("/v1/youtube/channel-videos", params)
        return {
            "videos": [self._parse_youtube_video(v) for v in (data.get("videos") or []) if v],
            "shorts": [self._parse_youtube_video(v) for v in (data.get("shorts") or []) if v],
        }

    def youtube_shorts_trending(self, region: str = "BR", count: int = 30) -> list[dict]:
        """Get trending YouTube Shorts via search. Cost: 1 credit."""
        result = self.youtube_search("shorts viral trending", count)
        return result.get("shorts", []) or result.get("videos", [])

    def youtube_comments(self, url: str, count: int = 30, cursor: str = "") -> dict:
        """Get comments from a YouTube video. Cost: 1 credit."""
        params = {"url": url, "count": min(count, 30)}
        if cursor:
            params["continuationToken"] = cursor
        data = self._request("/v1/youtube/video/comments", params)
        return {
            "comments": data.get("comments") or [],
            "continuation_token": data.get("continuationToken", ""),
        }

    def _parse_youtube_video(self, item: dict) -> dict:
        """Parse YouTube video into standard format."""
        desc = item.get("description", "") or ""
        hashtags = re.findall(r"#(\w+)", desc)

        video_id = str(item.get("videoId", "") or item.get("id", ""))
        url = item.get("url", "")
        if not url and video_id:
            url = f"https://www.youtube.com/watch?v={video_id}"

        # Parse published date - API returns publishedTime as ISO string
        published_at = None
        pub_str = (item.get("publishedTime") or item.get("publishedAt")
                   or item.get("publishDate") or item.get("published_at") or "")
        if pub_str:
            try:
                published_at = datetime.fromisoformat(pub_str.replace("Z", "+00:00")).replace(tzinfo=None)
            except (ValueError, AttributeError):
                try:
                    published_at = datetime.strptime(str(pub_str)[:10], "%Y-%m-%d")
                except (ValueError, AttributeError):
                    pass

        return {
            "platform": "youtube",
            "external_id": video_id,
            "url": url,
            "title": (item.get("title", "") or "")[:200],
            "description": desc[:500],
            "hashtags": hashtags[:20],
            "creator_username": item.get("channelTitle", "") or item.get("author", "") or (item.get("channel", "") if isinstance(item.get("channel"), str) else ""),
            "creator_id_external": item.get("channelId", ""),
            "creator_followers": int(item.get("subscriberCount", 0) or item.get("subscriber_count", 0) or 0),
            "views": int(item.get("viewCount", 0) or item.get("viewCountInt", 0) or item.get("views", 0) or 0),
            "likes": int(item.get("likeCount", 0) or item.get("likes", 0) or 0),
            "comments": int(item.get("commentCount", 0) or 0),
            "shares": 0,
            "duration": int(item.get("lengthSeconds", 0) or item.get("duration", 0) or 0),
            "thumbnail_url": item.get("thumbnail", "") or "",
            "published_at": published_at,
        }
