"""
Champion Videos Service - Vyral-style TikTok Shop winning video intelligence.

Features:
- Champion videos database with estimated revenue per video
- Script analysis (hooks, pain points, solutions, CTAs)
- Revenue estimation based on views + product price + conversion
- Smart filters by niche, country, revenue, views, sales
- Saved/favorites library
"""

import re
from datetime import datetime, timedelta

from sqlalchemy.orm import Session
from sqlalchemy import desc, or_, and_, func, String

from backend.models.video import Video
from backend.models.product import Product
from backend.models.saved_video import SavedVideo


# Estimated conversion rates by view range (TikTok Shop typical)
CONVERSION_RATES = {
    "mega": 0.008,    # 1M+ views → ~0.8% conversion
    "high": 0.012,    # 500K-1M views → ~1.2%
    "medium": 0.018,  # 100K-500K views → ~1.8%
    "low": 0.025,     # <100K views → ~2.5% (smaller but engaged audience)
}

# Average order values by category (R$)
AVG_ORDER_VALUES = {
    "moda": 89.90,
    "beleza": 59.90,
    "casa": 79.90,
    "eletronicos": 129.90,
    "esportes": 99.90,
    "default": 79.90,
}

# Niche keywords for classification
NICHE_KEYWORDS = {
    "moda": ["moda", "fashion", "roupa", "outfit", "look", "vestido", "blusa", "conjunto", "estilo", "style"],
    "beleza": ["beleza", "beauty", "skincare", "maquiagem", "makeup", "serum", "batom", "pele", "cabelo", "hair"],
    "casa": ["casa", "home", "decoracao", "cozinha", "kitchen", "organizador", "gadgets casa", "limpeza"],
    "eletronicos": ["tech", "gadget", "fone", "celular", "smartphone", "carregador", "smartwatch", "eletronic"],
    "esportes": ["fitness", "treino", "workout", "gym", "academia", "legging", "tenis", "esporte"],
    "saude": ["saude", "health", "vitamina", "suplemento", "bem estar", "wellness"],
    "pet": ["pet", "cachorro", "gato", "animal", "dog", "cat"],
    "bebe": ["bebe", "baby", "maternidade", "infantil", "crianca"],
    "automotivo": ["carro", "car", "auto", "moto", "acessorio carro"],
    "papelaria": ["papelaria", "caderno", "caneta", "stationery", "planner"],
}

# Hook patterns for script analysis
HOOK_PATTERNS = [
    r"^(voce precisa|you need|this is|isso e|olha so|look at|wait|espera|pov:|imagine)",
    r"^(como eu|how i|como fazer|how to|o segredo|the secret|ninguem sabe|nobody knows)",
    r"^(pare de|stop|nunca mais|never again|chega de|enough of)",
    r"^(descobri|i found|achei|testei|i tested|comprei|i bought)",
    r"(antes e depois|before.?after|transformacao|transformation)",
    r"(todo mundo|everyone|viral|trending|bombou|explodiu)",
    r"^\d+\s*(coisas|things|dicas|tips|motivos|reasons|formas|ways)",
]

CTA_PATTERNS = [
    r"(link na bio|link in bio|compre agora|buy now|aproveite|hurry)",
    r"(corre la|vai la|clica|click|acesse|access|confira|check out)",
    r"(promocao|sale|desconto|discount|frete gratis|free shipping)",
    r"(segue|follow|salva|save|compartilha|share|comenta|comment)",
    r"(cupom|coupon|codigo|code|oferta|offer|limitado|limited)",
    r"(loja|shop|store|comprar|buy|adquirir|get yours)",
]

PAIN_PATTERNS = [
    r"(cansad[oa] de|tired of|frustrad[oa]|problema com|problem with)",
    r"(dificil|difficult|complicado|complicated|nao consigo|can't|couldn't)",
    r"(gastei muito|spent too much|caro demais|too expensive|perdi tempo|wasted time)",
    r"(nao funciona|doesn't work|quebrou|broke|ruim|bad|pessimo|worst)",
]

SOLUTION_PATTERNS = [
    r"(a solucao|the solution|resolvi|solved|funciona|works|melhor|best)",
    r"(agora eu|now i|finalmente|finally|mudou minha vida|changed my life)",
    r"(esse produto|this product|recomendo|recommend|vale a pena|worth it)",
    r"(facil|easy|rapido|fast|simples|simple|pratico|practical)",
]


def estimate_revenue(views: int, price_str: str = "", category: str = "") -> dict:
    """Estimate revenue for a video based on views, product price, and conversion."""
    # Parse price
    price = _parse_price(price_str) if price_str else AVG_ORDER_VALUES.get(category, AVG_ORDER_VALUES["default"])

    # Select conversion rate
    if views >= 1_000_000:
        rate = CONVERSION_RATES["mega"]
    elif views >= 500_000:
        rate = CONVERSION_RATES["high"]
    elif views >= 100_000:
        rate = CONVERSION_RATES["medium"]
    else:
        rate = CONVERSION_RATES["low"]

    estimated_sales = int(views * rate)
    estimated_revenue = estimated_sales * price
    commission_rate = 0.10  # typical affiliate commission
    estimated_commission = estimated_revenue * commission_rate

    return {
        "estimated_sales": estimated_sales,
        "estimated_revenue": round(estimated_revenue, 2),
        "estimated_revenue_formatted": _format_currency(estimated_revenue),
        "estimated_commission": round(estimated_commission, 2),
        "estimated_commission_formatted": _format_currency(estimated_commission),
        "conversion_rate": rate,
        "product_price": round(price, 2),
        "product_price_formatted": _format_currency(price),
    }


def analyze_script(title: str, description: str) -> dict:
    """Analyze a video's script to extract hooks, pain points, solutions, and CTAs."""
    text = f"{title}\n{description}".lower().strip()
    lines = [l.strip() for l in text.split("\n") if l.strip()]

    hooks = []
    pain_points = []
    solutions = []
    ctas = []

    for line in lines:
        for pattern in HOOK_PATTERNS:
            if re.search(pattern, line, re.IGNORECASE):
                hooks.append(line[:200])
                break

        for pattern in PAIN_PATTERNS:
            if re.search(pattern, line, re.IGNORECASE):
                pain_points.append(line[:200])
                break

        for pattern in SOLUTION_PATTERNS:
            if re.search(pattern, line, re.IGNORECASE):
                solutions.append(line[:200])
                break

        for pattern in CTA_PATTERNS:
            if re.search(pattern, line, re.IGNORECASE):
                ctas.append(line[:200])
                break

    # If no explicit hook found, use the first line as hook
    if not hooks and lines:
        hooks = [lines[0][:200]]

    # Detect CTA from hashtags and common patterns in full text
    if not ctas:
        for pattern in CTA_PATTERNS:
            matches = re.findall(pattern, text, re.IGNORECASE)
            if matches:
                ctas.extend([m if isinstance(m, str) else m[0] for m in matches[:3]])
                break

    # Score the script quality
    score = 0
    if hooks:
        score += 25
    if pain_points:
        score += 25
    if solutions:
        score += 25
    if ctas:
        score += 25

    # Bonus points
    if len(description) > 100:
        score = min(100, score + 5)
    if any(emoji_check(text)):
        score = min(100, score + 5)

    return {
        "hooks": list(set(hooks))[:5],
        "pain_points": list(set(pain_points))[:5],
        "solutions": list(set(solutions))[:5],
        "ctas": list(set(ctas))[:5],
        "script_score": score,
        "script_grade": _grade(score),
        "word_count": len(text.split()),
        "has_price_mention": bool(re.search(r"R\$|r\$|\$\d|preco|price", text)),
        "has_urgency": bool(re.search(r"ultima|last|acaba|ends|limitado|limited|corre|hurry", text)),
        "has_social_proof": bool(re.search(r"vendidos|sold|\d+k|\d+m|mais vendido|best.?sell|todo mundo|everyone", text)),
    }


def classify_niche(title: str, description: str, hashtags: list = None) -> str:
    """Classify a video into a niche based on content."""
    text = f"{title} {description} {' '.join(hashtags or [])}".lower()
    scores = {}
    for niche, keywords in NICHE_KEYWORDS.items():
        score = sum(1 for kw in keywords if kw in text)
        if score > 0:
            scores[niche] = score
    if scores:
        return max(scores, key=scores.get)
    return "outros"


def get_champion_videos(
    db: Session,
    limit: int = 50,
    offset: int = 0,
    country: str = "all",
    niche: str = "",
    sort_by: str = "revenue",
    min_views: int = 10000,
    min_revenue: float = 0,
    search: str = "",
    days: int = 90,
) -> tuple[list[dict], int]:
    """Get champion videos - winning TikTok Shop videos with estimated revenue."""
    since = datetime.utcnow() - timedelta(days=days)

    query = db.query(Video).filter(
        Video.platform == "tiktok",
        Video.views >= min_views,
        Video.collected_at >= since,
        or_(
            and_(Video.shop_product_url != "", Video.shop_product_url.isnot(None)),
            Video.is_commerce_music == True,  # noqa: E712
            Video.with_shop_entry == True,  # noqa: E712
        ),
    )

    # Country filter
    if country == "br":
        query = query.filter(
            or_(
                Video.region == "BR",
                Video.language == "pt",
                Video.audio_language.like("pt%"),
            )
        )
    elif country == "us":
        query = query.filter(
            or_(
                Video.region == "US",
                Video.language == "en",
                Video.audio_language.like("en%"),
            )
        )
    elif country and country != "all":
        query = query.filter(Video.region == country.upper())

    # Search filter
    if search:
        query = query.filter(
            or_(
                Video.title.ilike(f"%{search}%"),
                Video.description.ilike(f"%{search}%"),
                Video.hashtags.cast(String).ilike(f"%{search}%"),
            )
        )

    # Niche filter
    if niche and niche in NICHE_KEYWORDS:
        conditions = []
        for kw in NICHE_KEYWORDS[niche]:
            conditions.append(Video.title.ilike(f"%{kw}%"))
            conditions.append(Video.description.ilike(f"%{kw}%"))
            conditions.append(Video.hashtags.cast(String).ilike(f"%{kw}%"))
        query = query.filter(or_(*conditions))

    total = query.count()

    # Sort
    sort_map = {
        "revenue": desc(Video.views),  # Revenue correlates with views for shop videos
        "views": desc(Video.views),
        "recent": desc(Video.collected_at),
        "viral_score": desc(Video.viral_score),
        "engagement": desc(Video.engagement_rate),
        "likes": desc(Video.likes),
    }
    order = sort_map.get(sort_by, desc(Video.views))
    videos = query.order_by(order).offset(offset).limit(limit).all()

    results = []
    for v in videos:
        hashtags_list = v.hashtags if isinstance(v.hashtags, list) else []
        niche_detected = classify_niche(v.title or "", v.description or "", hashtags_list)

        # Get product price if available
        product_price = ""
        product = None
        if v.shop_product_url:
            product = db.query(Product).filter(Product.url == v.shop_product_url).first()
            if product:
                product_price = product.price

        revenue = estimate_revenue(v.views, product_price, niche_detected)
        script = analyze_script(v.title or "", v.description or "")

        # Check if saved
        is_saved = db.query(SavedVideo).filter(SavedVideo.video_id == v.id).first() is not None

        item = {
            "id": v.id,
            "external_id": v.external_id,
            "url": v.url,
            "title": v.title,
            "description": v.description[:300] if v.description else "",
            "views": v.views,
            "views_formatted": v.views_formatted,
            "likes": v.likes,
            "comments": v.comments,
            "shares": v.shares,
            "duration": v.duration,
            "duration_formatted": v.duration_formatted,
            "viral_score": v.viral_score,
            "engagement_rate": v.engagement_rate,
            "thumbnail_url": v.thumbnail_url,
            "creator_username": v.creator.username if v.creator else "",
            "creator_followers": v.creator_followers,
            "shop_product_url": v.shop_product_url,
            "region": v.region or "",
            "language": v.language or "",
            "published_at": v.published_at.isoformat() if v.published_at else None,
            "collected_at": v.collected_at.isoformat() if v.collected_at else None,
            "niche": niche_detected,
            "is_saved": is_saved,
            # Revenue data
            **revenue,
            # Script analysis
            "script": script,
            # Product data
            "product": {
                "title": product.title if product else "",
                "price": product.price if product else "",
                "sold_count": product.sold_count if product else 0,
                "sold_formatted": product.sold_formatted if product else "0",
                "image": product.image if product else "",
                "rating": product.rating if product else 0,
            } if product else None,
        }

        # Filter by min revenue after estimation
        if min_revenue > 0 and revenue["estimated_revenue"] < min_revenue:
            total -= 1
            continue

        results.append(item)

    return results, total


def get_champion_stats(db: Session) -> dict:
    """Get overall stats for the champion videos dashboard."""
    since_30d = datetime.utcnow() - timedelta(days=30)
    since_7d = datetime.utcnow() - timedelta(days=7)

    base_filter = and_(
        Video.platform == "tiktok",
        or_(
            and_(Video.shop_product_url != "", Video.shop_product_url.isnot(None)),
            Video.is_commerce_music == True,  # noqa: E712
            Video.with_shop_entry == True,  # noqa: E712
        ),
    )

    total_videos = db.query(func.count(Video.id)).filter(base_filter).scalar() or 0
    videos_30d = db.query(func.count(Video.id)).filter(base_filter, Video.collected_at >= since_30d).scalar() or 0
    videos_7d = db.query(func.count(Video.id)).filter(base_filter, Video.collected_at >= since_7d).scalar() or 0

    total_views = db.query(func.sum(Video.views)).filter(base_filter).scalar() or 0
    avg_views = db.query(func.avg(Video.views)).filter(base_filter).scalar() or 0

    total_products = db.query(func.count(Product.id)).scalar() or 0
    total_saved = db.query(func.count(SavedVideo.id)).scalar() or 0

    # Top niches
    br_count = db.query(func.count(Video.id)).filter(
        base_filter,
        or_(Video.region == "BR", Video.language == "pt"),
    ).scalar() or 0

    us_count = db.query(func.count(Video.id)).filter(
        base_filter,
        or_(Video.region == "US", Video.language == "en"),
    ).scalar() or 0

    return {
        "total_videos": total_videos,
        "videos_30d": videos_30d,
        "videos_7d": videos_7d,
        "total_views": total_views,
        "total_views_formatted": _format_number(total_views),
        "avg_views": int(avg_views),
        "avg_views_formatted": _format_number(int(avg_views)),
        "total_products": total_products,
        "total_saved": total_saved,
        "br_count": br_count,
        "us_count": us_count,
    }


def save_video(db: Session, video_id: int, notes: str = "", tags: str = "", folder: str = "geral") -> dict:
    """Save a video to the user's library."""
    existing = db.query(SavedVideo).filter(SavedVideo.video_id == video_id).first()
    if existing:
        existing.notes = notes or existing.notes
        existing.tags = tags or existing.tags
        existing.folder = folder or existing.folder
        db.commit()
        return existing.to_dict()

    saved = SavedVideo(video_id=video_id, notes=notes, tags=tags, folder=folder)
    db.add(saved)
    db.commit()
    db.refresh(saved)
    return saved.to_dict()


def unsave_video(db: Session, video_id: int) -> bool:
    """Remove a video from the saved library."""
    saved = db.query(SavedVideo).filter(SavedVideo.video_id == video_id).first()
    if saved:
        db.delete(saved)
        db.commit()
        return True
    return False


def get_saved_videos(db: Session, folder: str = "", limit: int = 50, offset: int = 0) -> tuple[list[dict], int]:
    """Get all saved videos with their data."""
    query = db.query(SavedVideo)
    if folder:
        query = query.filter(SavedVideo.folder == folder)

    total = query.count()
    saved_items = query.order_by(desc(SavedVideo.saved_at)).offset(offset).limit(limit).all()

    results = []
    for sv in saved_items:
        v = sv.video
        if not v:
            continue

        hashtags_list = v.hashtags if isinstance(v.hashtags, list) else []
        niche_detected = classify_niche(v.title or "", v.description or "", hashtags_list)
        revenue = estimate_revenue(v.views, "", niche_detected)

        results.append({
            "saved_id": sv.id,
            "video_id": v.id,
            "notes": sv.notes,
            "tags": sv.tags,
            "folder": sv.folder,
            "saved_at": sv.saved_at.isoformat() if sv.saved_at else None,
            "external_id": v.external_id,
            "url": v.url,
            "title": v.title,
            "description": v.description[:200] if v.description else "",
            "views": v.views,
            "views_formatted": v.views_formatted,
            "likes": v.likes,
            "viral_score": v.viral_score,
            "thumbnail_url": v.thumbnail_url,
            "creator_username": v.creator.username if v.creator else "",
            "niche": niche_detected,
            **revenue,
        })

    return results, total


def get_saved_folders(db: Session) -> list[dict]:
    """Get list of folders with video counts."""
    results = (
        db.query(SavedVideo.folder, func.count(SavedVideo.id))
        .group_by(SavedVideo.folder)
        .all()
    )
    return [{"folder": f or "geral", "count": c} for f, c in results]


def emoji_check(text: str) -> list:
    """Check if text contains emojis."""
    emoji_pattern = re.compile(
        "[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF\U0001F900-\U0001F9FF]"
    )
    return emoji_pattern.findall(text)


def _parse_price(price_str: str) -> float:
    if not price_str:
        return 0.0
    price_str = str(price_str).split("-")[0].strip()
    cleaned = re.sub(r"[^\d.,]", "", price_str)
    if "," in cleaned and "." in cleaned:
        cleaned = cleaned.replace(".", "").replace(",", ".")
    elif "," in cleaned:
        cleaned = cleaned.replace(",", ".")
    try:
        return float(cleaned)
    except ValueError:
        return 0.0


def _format_currency(value: float) -> str:
    if value >= 1_000_000:
        return f"R$ {value / 1_000_000:.1f}M"
    if value >= 1_000:
        return f"R$ {value / 1_000:.1f}K"
    return f"R$ {value:,.2f}".replace(",", "X").replace(".", ",").replace("X", ".")


def _format_number(n: int) -> str:
    if n >= 1_000_000_000:
        return f"{n / 1_000_000_000:.1f}B"
    if n >= 1_000_000:
        return f"{n / 1_000_000:.1f}M"
    if n >= 1_000:
        return f"{n / 1_000:.1f}K"
    return str(n)


def _grade(score: int) -> str:
    if score >= 80:
        return "A"
    if score >= 60:
        return "B"
    if score >= 40:
        return "C"
    return "D"
