from datetime import datetime, timedelta
from collections import Counter

from sqlalchemy.orm import Session
from sqlalchemy import func, desc

from backend.models.video import Video
from backend.models.trend import Trend
from backend.models.creator import Creator


class TrendAnalyzer:
    """Analyzes trends from collected video data."""

    def analyze_hashtags(
        self, db: Session, platform: str = "", days: int = 7, limit: int = 30
    ) -> list[dict]:
        """Find the most used and highest-performing hashtags."""
        since = datetime.utcnow() - timedelta(days=days)
        query = db.query(Video).filter(Video.collected_at >= since)
        if platform:
            query = query.filter(Video.platform == platform)

        videos = query.all()
        hashtag_stats: dict[str, dict] = {}

        for video in videos:
            tags = video.hashtags or []
            if isinstance(tags, str):
                tags = [t.strip() for t in tags.split(",") if t.strip()]

            for tag in tags:
                tag = tag.lower().strip("#")
                if not tag or len(tag) < 2:
                    continue
                if tag not in hashtag_stats:
                    hashtag_stats[tag] = {
                        "name": tag,
                        "count": 0,
                        "total_views": 0,
                        "total_likes": 0,
                        "total_engagement": 0.0,
                        "avg_viral_score": 0.0,
                        "platforms": set(),
                        "scores": [],
                    }
                h = hashtag_stats[tag]
                h["count"] += 1
                h["total_views"] += video.views
                h["total_likes"] += video.likes
                h["total_engagement"] += video.engagement_rate
                h["scores"].append(video.viral_score)
                h["platforms"].add(video.platform)

        results = []
        for tag, stats in hashtag_stats.items():
            scores = stats.pop("scores")
            stats["avg_viral_score"] = round(sum(scores) / len(scores), 1) if scores else 0
            stats["avg_views"] = stats["total_views"] // max(stats["count"], 1)
            stats["platforms"] = list(stats["platforms"])
            results.append(stats)

        results.sort(key=lambda x: (x["count"] * x["avg_viral_score"]), reverse=True)
        return results[:limit]

    def analyze_content_patterns(
        self, db: Session, platform: str = "", days: int = 30
    ) -> dict:
        """Analyze patterns in viral content."""
        since = datetime.utcnow() - timedelta(days=days)
        query = db.query(Video).filter(
            Video.collected_at >= since,
            Video.viral_score >= 40,
        )
        if platform:
            query = query.filter(Video.platform == platform)

        videos = query.all()
        if not videos:
            return self._empty_patterns()

        # Duration analysis
        durations = [v.duration for v in videos if v.duration > 0]
        duration_buckets = {"0-15s": 0, "15-30s": 0, "30-60s": 0, "1-3min": 0, "3-10min": 0, "10min+": 0}
        for d in durations:
            if d <= 15:
                duration_buckets["0-15s"] += 1
            elif d <= 30:
                duration_buckets["15-30s"] += 1
            elif d <= 60:
                duration_buckets["30-60s"] += 1
            elif d <= 180:
                duration_buckets["1-3min"] += 1
            elif d <= 600:
                duration_buckets["3-10min"] += 1
            else:
                duration_buckets["10min+"] += 1

        # Best posting hours (when virals were published)
        hour_counts = Counter()
        day_counts = Counter()
        for v in videos:
            if v.published_at:
                hour_counts[v.published_at.hour] += 1
                day_counts[v.published_at.strftime("%A")] += 1

        best_hours = [
            {"hour": h, "label": f"{h:02d}:00", "count": c}
            for h, c in hour_counts.most_common(24)
        ]
        best_hours.sort(key=lambda x: x["hour"])

        day_map = {
            "Monday": "Segunda", "Tuesday": "Terça", "Wednesday": "Quarta",
            "Thursday": "Quinta", "Friday": "Sexta", "Saturday": "Sábado", "Sunday": "Domingo",
        }
        best_days = [
            {"day": day_map.get(d, d), "count": c}
            for d, c in day_counts.most_common(7)
        ]

        # Engagement by platform
        platform_stats = {}
        for v in videos:
            if v.platform not in platform_stats:
                platform_stats[v.platform] = {
                    "count": 0, "total_score": 0, "total_views": 0,
                    "total_engagement": 0,
                }
            p = platform_stats[v.platform]
            p["count"] += 1
            p["total_score"] += v.viral_score
            p["total_views"] += v.views
            p["total_engagement"] += v.engagement_rate

        for p, stats in platform_stats.items():
            n = max(stats["count"], 1)
            stats["avg_score"] = round(stats["total_score"] / n, 1)
            stats["avg_views"] = stats["total_views"] // n
            stats["avg_engagement"] = round(stats["total_engagement"] / n, 2)

        # Score distribution
        score_dist = {"0-20": 0, "20-40": 0, "40-60": 0, "60-80": 0, "80-100": 0}
        for v in videos:
            if v.viral_score < 20:
                score_dist["0-20"] += 1
            elif v.viral_score < 40:
                score_dist["20-40"] += 1
            elif v.viral_score < 60:
                score_dist["40-60"] += 1
            elif v.viral_score < 80:
                score_dist["60-80"] += 1
            else:
                score_dist["80-100"] += 1

        avg_duration = sum(durations) / len(durations) if durations else 0

        return {
            "total_analyzed": len(videos),
            "duration": {
                "buckets": duration_buckets,
                "average_seconds": round(avg_duration),
                "optimal_range": self._find_optimal_duration(videos),
            },
            "posting_times": {
                "best_hours": best_hours,
                "best_days": best_days,
            },
            "platform_performance": platform_stats,
            "score_distribution": score_dist,
        }

    def get_trending_now(
        self, db: Session, hours: int = 48, limit: int = 20
    ) -> list[dict]:
        """Get videos trending right now (high score + recent)."""
        since = datetime.utcnow() - timedelta(hours=hours)
        videos = (
            db.query(Video)
            .filter(Video.collected_at >= since, Video.viral_score >= 50)
            .order_by(desc(Video.viral_score))
            .limit(limit)
            .all()
        )
        return [
            {
                "id": v.id,
                "platform": v.platform,
                "title": v.title[:100],
                "url": v.url,
                "views": v.views,
                "viral_score": v.viral_score,
                "engagement_rate": v.engagement_rate,
                "thumbnail_url": v.thumbnail_url,
                "creator": v.creator.username if v.creator else "",
            }
            for v in videos
        ]

    def save_hashtag_trends(self, db: Session, hashtag_data: list[dict]):
        """Persist hashtag trend data to the trends table."""
        for h in hashtag_data:
            existing = (
                db.query(Trend)
                .filter_by(trend_type="hashtag", name=h["name"])
                .first()
            )
            if existing:
                existing.volume = h["total_views"]
                existing.video_count = h["count"]
                existing.growth_rate = h["avg_viral_score"]
                existing.last_updated = datetime.utcnow()
            else:
                trend = Trend(
                    platform=h["platforms"][0] if h["platforms"] else "multi",
                    trend_type="hashtag",
                    name=h["name"],
                    volume=h["total_views"],
                    video_count=h["count"],
                    growth_rate=h["avg_viral_score"],
                )
                db.add(trend)
        db.commit()

    def _find_optimal_duration(self, videos: list) -> str:
        """Find the duration range with highest average viral score."""
        buckets = {
            "0-15s": [], "15-30s": [], "30-60s": [],
            "1-3min": [], "3-10min": [], "10min+": [],
        }
        for v in videos:
            d = v.duration
            if d <= 0:
                continue
            if d <= 15:
                buckets["0-15s"].append(v.viral_score)
            elif d <= 30:
                buckets["15-30s"].append(v.viral_score)
            elif d <= 60:
                buckets["30-60s"].append(v.viral_score)
            elif d <= 180:
                buckets["1-3min"].append(v.viral_score)
            elif d <= 600:
                buckets["3-10min"].append(v.viral_score)
            else:
                buckets["10min+"].append(v.viral_score)

        best = max(
            buckets.items(),
            key=lambda x: (sum(x[1]) / len(x[1])) if x[1] else 0,
        )
        return best[0] if best[1] else "N/A"

    def _empty_patterns(self) -> dict:
        return {
            "total_analyzed": 0,
            "duration": {"buckets": {}, "average_seconds": 0, "optimal_range": "N/A"},
            "posting_times": {"best_hours": [], "best_days": []},
            "platform_performance": {},
            "score_distribution": {},
        }
