"""
Apify integration for social media scraping.

Pricing:
- Free: $5/month in credits (~1,000 TikTok results)
- Starter: $39/month
- Scale: $199/month

Actors used:
- clockworks/tiktok-scraper: TikTok profiles, hashtags, trending
- apidojo/instagram-scraper: Instagram hashtags, profiles
- apidojo/tiktok-scraper: Alternative TikTok scraper

Docs: https://apify.com/
"""

import re
import httpx
from datetime import datetime


class ApifyScraper:
    """Apify actor runner for social media scraping."""

    BASE_URL = "https://api.apify.com/v2"

    # Pre-built actor IDs
    ACTORS = {
        "tiktok_scraper": "clockworks~tiktok-scraper",
        "tiktok_trending": "data_xplorer~tiktok-trends",
        "tiktok_hashtag": "api-empire~tiktok-trending-hashtags-analytics-scraper",
        "instagram_scraper": "apidojo~instagram-scraper",
        "instagram_hashtag": "apidojo~instagram-hashtag-scraper",
    }

    def __init__(self, api_token: str):
        if not api_token:
            raise ValueError(
                "Apify API token required. "
                "Get one at https://apify.com ($5 free credits)"
            )
        self.api_token = api_token

    def _run_actor(
        self, actor_id: str, run_input: dict, timeout_secs: int = 120
    ) -> list[dict]:
        """Run an Apify actor and wait for results."""
        url = f"{self.BASE_URL}/acts/{actor_id}/run-sync-get-dataset-items"
        params = {"token": self.api_token, "timeout": timeout_secs}
        try:
            with httpx.Client(timeout=timeout_secs + 10) as client:
                resp = client.post(url, json=run_input, params=params)
                resp.raise_for_status()
                return resp.json() if resp.text else []
        except httpx.HTTPStatusError as e:
            if e.response.status_code == 402:
                print("[Apify] Insufficient credits. Top up at https://apify.com/pricing")
            else:
                print(f"[Apify] HTTP error {e.response.status_code}: {e.response.text[:200]}")
            return []
        except Exception as e:
            print(f"[Apify] Error running actor {actor_id}: {e}")
            return []

    # ─── TikTok ─────────────────────────────────────────────────

    def tiktok_user_videos(
        self, username: str, max_results: int = 30
    ) -> list[dict]:
        """Get videos from a TikTok user profile."""
        run_input = {
            "profiles": [f"https://www.tiktok.com/@{username.lstrip('@')}"],
            "resultsPerPage": min(max_results, 50),
            "shouldDownloadVideos": False,
        }
        items = self._run_actor(self.ACTORS["tiktok_scraper"], run_input)
        return [self._parse_tiktok(item) for item in items if item]

    def tiktok_hashtag_videos(
        self, hashtag: str, max_results: int = 30
    ) -> list[dict]:
        """Get TikTok videos by hashtag."""
        run_input = {
            "hashtags": [hashtag.strip("#")],
            "resultsPerPage": min(max_results, 50),
            "shouldDownloadVideos": False,
        }
        items = self._run_actor(self.ACTORS["tiktok_scraper"], run_input)
        return [self._parse_tiktok(item) for item in items if item]

    def tiktok_trending_hashtags(
        self, region: str = "BR", period: int = 7
    ) -> list[dict]:
        """Get trending TikTok hashtags via Apify."""
        run_input = {
            "countryCode": region,
            "period": period,
        }
        items = self._run_actor(self.ACTORS["tiktok_hashtag"], run_input, timeout_secs=60)
        results = []
        for item in items:
            results.append({
                "platform": "tiktok",
                "trend_type": "hashtag",
                "name": item.get("name", "") or item.get("hashtag", ""),
                "video_count": item.get("videoCount", 0),
                "view_count": item.get("viewCount", 0),
                "region": region,
            })
        return results

    def _parse_tiktok(self, item: dict) -> dict:
        """Parse Apify TikTok result into standard format."""
        desc = item.get("text", "") or item.get("desc", "") or ""
        hashtags = re.findall(r"#(\w+)", desc)
        author = item.get("authorMeta", {}) or {}

        published_at = None
        ts = item.get("createTimeISO") or item.get("createTime")
        if ts:
            try:
                if isinstance(ts, str):
                    published_at = datetime.fromisoformat(ts.replace("Z", "+00:00"))
                else:
                    published_at = datetime.fromtimestamp(int(ts))
            except (ValueError, TypeError, OSError):
                pass

        return {
            "platform": "tiktok",
            "external_id": str(item.get("id", "")),
            "url": item.get("webVideoUrl", "") or f"https://www.tiktok.com/@{author.get('name', '')}/video/{item.get('id', '')}",
            "title": desc[:200],
            "description": desc[:500],
            "hashtags": hashtags[:20],
            "creator_username": author.get("name", "") or author.get("uniqueId", ""),
            "creator_display_name": author.get("nickName", "") or author.get("nickname", ""),
            "views": int(item.get("playCount", 0) or item.get("videoMeta", {}).get("playCount", 0) or 0),
            "likes": int(item.get("diggCount", 0) or item.get("likes", 0) or 0),
            "comments": int(item.get("commentCount", 0) or item.get("comments", 0) or 0),
            "shares": int(item.get("shareCount", 0) or item.get("shares", 0) or 0),
            "duration": int(item.get("videoMeta", {}).get("duration", 0) or item.get("duration", 0) or 0),
            "thumbnail_url": item.get("covers", {}).get("default", "") or "",
            "published_at": published_at,
        }

    # ─── Instagram ──────────────────────────────────────────────

    def instagram_user_reels(
        self, username: str, max_results: int = 30
    ) -> list[dict]:
        """Get reels from an Instagram user."""
        run_input = {
            "directUrls": [f"https://www.instagram.com/{username.lstrip('@')}/reels/"],
            "resultsLimit": min(max_results, 50),
            "resultsType": "posts",
        }
        items = self._run_actor(self.ACTORS["instagram_scraper"], run_input)
        return [self._parse_instagram(item) for item in items if item]

    def instagram_hashtag_posts(
        self, hashtag: str, max_results: int = 30
    ) -> list[dict]:
        """Get Instagram posts by hashtag."""
        run_input = {
            "hashtags": [hashtag.strip("#")],
            "resultsLimit": min(max_results, 50),
            "resultsType": "posts",
        }
        items = self._run_actor(self.ACTORS["instagram_hashtag"], run_input)
        return [self._parse_instagram(item) for item in items if item]

    def _parse_instagram(self, item: dict) -> dict:
        """Parse Apify Instagram result into standard format."""
        caption = item.get("caption", "") or ""
        hashtags = re.findall(r"#(\w+)", caption)

        published_at = None
        ts = item.get("timestamp") or item.get("taken_at")
        if ts:
            try:
                if isinstance(ts, str):
                    published_at = datetime.fromisoformat(ts.replace("Z", "+00:00"))
                else:
                    published_at = datetime.fromtimestamp(int(ts))
            except (ValueError, TypeError, OSError):
                pass

        owner = item.get("ownerUsername", "") or item.get("owner", {}).get("username", "")
        shortcode = item.get("shortCode", "") or item.get("code", "")

        return {
            "platform": "instagram",
            "external_id": str(item.get("id", "") or item.get("pk", "")),
            "url": f"https://www.instagram.com/reel/{shortcode}/" if shortcode else item.get("url", ""),
            "title": caption[:200],
            "description": caption[:500],
            "hashtags": hashtags[:20],
            "creator_username": owner,
            "creator_display_name": item.get("ownerFullName", "") or owner,
            "views": int(item.get("videoPlayCount", 0) or item.get("videoViewCount", 0) or 0),
            "likes": int(item.get("likesCount", 0) or item.get("like_count", 0) or 0),
            "comments": int(item.get("commentsCount", 0) or item.get("comment_count", 0) or 0),
            "shares": 0,
            "duration": int(item.get("videoDuration", 0) or 0),
            "thumbnail_url": item.get("displayUrl", "") or item.get("thumbnailUrl", ""),
            "published_at": published_at,
        }
