"""
Cross-Platform Replicator - Find viral content on one platform not yet on others.
Also includes Affiliate Product Matcher and Engagement Heatmap.
"""

from datetime import datetime, timedelta
from collections import Counter

from sqlalchemy.orm import Session
from backend.models.video import Video


def find_replicable_content(sc, keyword: str, source_platform: str = "tiktok", count: int = 15) -> dict:
    """Find viral videos on source platform and check if similar exists on others."""
    platforms = ["tiktok", "instagram", "youtube"]
    platforms.remove(source_platform) if source_platform in platforms else None

    # Get viral from source
    source_videos = []
    try:
        if source_platform == "tiktok":
            source_videos = sc.tiktok_search_top(keyword, count)
        elif source_platform == "instagram":
            source_videos = sc.instagram_reels_search(keyword, count)
        elif source_platform == "youtube":
            result = sc.youtube_search(keyword, count)
            source_videos = result.get("shorts", []) + result.get("videos", [])
    except Exception:
        pass

    # Sort by views
    source_videos.sort(key=lambda x: x.get("views", 0), reverse=True)

    # Check other platforms for similar
    other_results = {}
    for p in platforms:
        try:
            if p == "tiktok":
                other_results[p] = sc.tiktok_search_top(keyword, 10)
            elif p == "instagram":
                other_results[p] = sc.instagram_reels_search(keyword, 10)
            elif p == "youtube":
                result = sc.youtube_search(keyword, 10)
                other_results[p] = result.get("shorts", []) + result.get("videos", [])
        except Exception:
            other_results[p] = []

    # Find creators on source that aren't on target platforms
    source_creators = {v.get("creator_username", "") for v in source_videos if v.get("creator_username")}
    other_creators = set()
    for vids in other_results.values():
        for v in vids:
            c = v.get("creator_username", "")
            if c:
                other_creators.add(c)

    unique_to_source = source_creators - other_creators

    # Opportunities: videos with high views from creators not on other platforms
    opportunities = []
    for v in source_videos[:10]:
        creator = v.get("creator_username", "")
        is_unique = creator in unique_to_source
        opportunities.append({
            **v,
            "is_unique_creator": is_unique,
            "replication_score": _calc_replication_score(v, is_unique),
            "suggestion": f"Adaptar para {', '.join(platforms)}" if is_unique else "Conteudo ja presente em multiplas plataformas",
        })

    opportunities.sort(key=lambda x: x.get("replication_score", 0), reverse=True)

    return {
        "keyword": keyword,
        "source_platform": source_platform,
        "target_platforms": platforms,
        "source_videos": len(source_videos),
        "opportunities": opportunities,
        "unique_creators": list(unique_to_source)[:10],
        "other_platform_counts": {p: len(v) for p, v in other_results.items()},
    }


def match_affiliate_products(sc, db: Session, niche_keywords: list[str]) -> list[dict]:
    """Match viral videos with TikTok Shop products for affiliate opportunities."""
    matches = []
    seen_products = set()

    for kw in niche_keywords[:5]:
        # Find viral videos
        try:
            videos = sc.tiktok_search_top(kw, 15)
        except Exception:
            continue

        # Find related products
        try:
            products = sc.tiktok_shop_search(kw, 20)
        except Exception:
            products = []

        # Match videos with products
        for p in products:
            pid = p.get("product_id", "")
            if pid in seen_products:
                continue
            seen_products.add(pid)

            # Find videos that could promote this product
            related_vids = []
            for v in videos:
                if v.get("views", 0) > 10000:
                    related_vids.append({
                        "url": v.get("url", ""),
                        "views": v.get("views", 0),
                        "creator": v.get("creator_username", ""),
                        "engagement": _calc_engagement(v),
                    })

            if related_vids:
                matches.append({
                    "product": p,
                    "keyword": kw,
                    "related_videos": related_vids[:5],
                    "estimated_reach": sum(v["views"] for v in related_vids),
                    "opportunity_score": _calc_affiliate_score(p, related_vids),
                })

    matches.sort(key=lambda x: x.get("opportunity_score", 0), reverse=True)
    return matches


def engagement_heatmap(db: Session, platform: str = "", niche: str = "", days: int = 30) -> dict:
    """Generate engagement heatmap by hour and day of week."""
    since = datetime.utcnow() - timedelta(days=days)
    q = db.query(Video).filter(Video.published_at.isnot(None), Video.published_at >= since)
    if platform:
        q = q.filter(Video.platform == platform)
    if niche:
        q = q.filter(Video.title.ilike(f"%{niche}%") | Video.description.ilike(f"%{niche}%"))

    videos = q.all()

    # Build heatmap: [day_of_week][hour] = {count, total_views, total_engagement}
    heatmap = {}
    day_names = ["Segunda", "Terca", "Quarta", "Quinta", "Sexta", "Sabado", "Domingo"]

    for day in range(7):
        heatmap[day] = {}
        for hour in range(24):
            heatmap[day][hour] = {"count": 0, "views": 0, "engagement": 0}

    for v in videos:
        if v.published_at:
            day = v.published_at.weekday()
            hour = v.published_at.hour
            heatmap[day][hour]["count"] += 1
            heatmap[day][hour]["views"] += (v.views or 0)
            eng = (v.likes or 0) + (v.comments or 0) + (v.shares or 0)
            heatmap[day][hour]["engagement"] += eng

    # Calculate averages and find best slots
    best_slots = []
    for day in range(7):
        for hour in range(24):
            cell = heatmap[day][hour]
            if cell["count"] > 0:
                cell["avg_views"] = round(cell["views"] / cell["count"])
                cell["avg_engagement"] = round(cell["engagement"] / cell["count"])
                best_slots.append({
                    "day": day,
                    "day_name": day_names[day],
                    "hour": hour,
                    "count": cell["count"],
                    "avg_views": cell["avg_views"],
                    "avg_engagement": cell["avg_engagement"],
                })

    best_slots.sort(key=lambda x: x["avg_views"], reverse=True)

    # Format for frontend
    formatted = []
    for day in range(7):
        row = {"day": day_names[day]}
        for hour in range(24):
            cell = heatmap[day][hour]
            row[str(hour)] = cell.get("avg_views", 0)
        formatted.append(row)

    return {
        "heatmap": formatted,
        "best_slots": best_slots[:10],
        "total_videos_analyzed": len(videos),
        "platform": platform or "all",
        "niche": niche or "all",
    }


def _calc_replication_score(video: dict, is_unique: bool) -> int:
    score = 30 if is_unique else 10
    views = video.get("views", 0)
    if views > 1000000: score += 30
    elif views > 100000: score += 20
    elif views > 10000: score += 10

    engagement = _calc_engagement(video)
    if engagement > 5: score += 20
    elif engagement > 2: score += 10

    return min(100, score)


def _calc_engagement(video: dict) -> float:
    views = video.get("views", 0) or 1
    likes = video.get("likes", 0) or 0
    comments = video.get("comments", 0) or 0
    return round((likes + comments) / views * 100, 2)


def _calc_affiliate_score(product: dict, videos: list[dict]) -> int:
    score = 0
    sold = product.get("sold_count", 0)
    if sold > 10000: score += 30
    elif sold > 1000: score += 20
    elif sold > 100: score += 10

    rating = product.get("rating", 0)
    if rating >= 4.5: score += 20
    elif rating >= 4.0: score += 10

    total_views = sum(v.get("views", 0) for v in videos)
    if total_views > 1000000: score += 30
    elif total_views > 100000: score += 20
    elif total_views > 10000: score += 10

    return min(100, score)
