"""
Enhanced FeedbackLearner — learns from individual users AND collective platform patterns.

New features:
- Platform-wide trend tracking (what people search and find useful)
- Session-based learning for anonymous users
- Collective signals inform query expansion and ranking
- Negative signal suppression (don't keep showing what people dismiss)
"""

import logging
from typing import Optional

logger = logging.getLogger(__name__)

# Deltas for preference weight adjustments
POSITIVE_DELTA = 0.08
NEGATIVE_DELTA = 0.06
CLICK_DELTA = 0.04
CART_DELTA = 0.10
MAX_WEIGHT = 1.0
MIN_WEIGHT = 0.0


def _clamp(val: float) -> float:
    return max(MIN_WEIGHT, min(MAX_WEIGHT, val))


def record_message_feedback(
    message_id: int,
    feedback: str,
    note: str = "",
    user=None,
) -> bool:
    """
    Persist thumbs up/down on a Message and update user preference profile.
    Also updates platform-wide trend signals.
    """
    from chat.models import Message, ProductInteraction

    try:
        msg = Message.objects.select_related("conversation__user").get(
            id=message_id, role="assistant"
        )
    except Message.DoesNotExist:
        return False

    msg.feedback = feedback
    msg.feedback_note = note
    msg.save(update_fields=["feedback", "feedback_note"])

    products = msg.product_data or []
    if isinstance(products, list) and products:
        action = "positive_feedback" if feedback == "up" else "negative_feedback"
        query_context = (msg.metadata or {}).get("query", {})
        conv = msg.conversation
        session_key = conv.session_key if conv else ""

        for p in products:
            if not isinstance(p, dict):
                continue
            try:
                ProductInteraction.objects.create(
                    conversation=conv,
                    user=user,
                    session_key=session_key,
                    product_name=p.get("name", ""),
                    store_name=p.get("store_name", ""),
                    store_slug=p.get("store_slug", ""),
                    category=p.get("category", ""),
                    brand=p.get("brand", ""),
                    price=p.get("price"),
                    currency=p.get("currency", ""),
                    query_context=query_context,
                    action=action,
                )
            except Exception as exc:
                logger.warning("ProductInteraction create failed: %s", exc)

        # Update per-user profile
        if user and user.is_authenticated:
            _update_preference_profile_from_feedback(user, products, feedback, query_context)

        # Update platform-wide collective signals
        _update_collective_signals(products, action, query_context)

    return True


def record_product_interaction(
    session_key: str,
    product: dict,
    action: str,
    query_context: Optional[dict] = None,
    user=None,
    conversation_id: Optional[str] = None,
) -> None:
    """Record a user's interaction with a product card."""
    from chat.models import ProductInteraction, Conversation

    conv = None
    if conversation_id:
        try:
            conv = Conversation.objects.get(id=conversation_id)
        except Conversation.DoesNotExist:
            pass

    try:
        ProductInteraction.objects.create(
            conversation=conv,
            user=user,
            session_key=session_key or "",
            product_name=product.get("name", ""),
            store_name=product.get("store_name", ""),
            store_slug=product.get("store_slug", ""),
            category=product.get("category", ""),
            brand=product.get("brand", ""),
            price=product.get("price"),
            currency=product.get("currency", ""),
            query_context=query_context,
            action=action,
        )
    except Exception as exc:
        logger.warning("record_product_interaction failed: %s", exc)

    if user and action in ("click", "add_cart", "purchase"):
        _update_preference_profile_from_interaction(user, product, action)

    # Always update collective signals for positive actions
    if action in ("click", "add_cart", "purchase", "positive_feedback"):
        _update_collective_signals([product], action, query_context)


def _update_collective_signals(products: list, action: str, query_context: dict):
    """
    Update platform-wide signals that inform query expansion for ALL users.
    Tracks which categories, brands, and query terms lead to positive outcomes.
    """
    try:
        from django.core.cache import cache
        is_positive = action in ("click", "add_cart", "purchase", "positive_feedback")

        for p in products:
            if not isinstance(p, dict):
                continue
            category = (p.get("category") or "").strip().lower()
            brand = (p.get("brand") or "").strip().lower()

            if category and is_positive:
                key = f"aca:collective:cat:{category}"
                count = cache.get(key, 0)
                cache.set(key, count + 1, timeout=86400 * 30)  # 30-day rolling

            if brand and is_positive:
                key = f"aca:collective:brand:{brand}"
                count = cache.get(key, 0)
                cache.set(key, count + 1, timeout=86400 * 30)

        # Track query terms that led to successful outcomes
        if query_context and is_positive:
            q_text = str(query_context.get("q", "") or query_context.get("category", "")).strip().lower()
            if q_text:
                key = f"aca:collective:query:{q_text[:50]}"
                count = cache.get(key, 0)
                cache.set(key, count + 1, timeout=86400 * 30)

    except Exception as exc:
        logger.debug("Collective signal update failed: %s", exc)


def get_collective_popular_categories(limit: int = 10) -> list:
    """Return most interacted-with categories platform-wide."""
    try:
        from chat.models import ProductInteraction
        from django.db.models import Count
        results = (
            ProductInteraction.objects
            .filter(action__in=("click", "add_cart", "purchase", "positive_feedback"))
            .exclude(category="")
            .values("category")
            .annotate(count=Count("id"))
            .order_by("-count")[:limit]
        )
        return [r["category"] for r in results]
    except Exception:
        return []


def get_collective_popular_brands(category: str = "", limit: int = 8) -> list:
    """Return most interacted-with brands platform-wide, optionally filtered by category."""
    try:
        from chat.models import ProductInteraction
        from django.db.models import Count
        qs = ProductInteraction.objects.filter(
            action__in=("click", "add_cart", "purchase", "positive_feedback")
        ).exclude(brand="")
        if category:
            qs = qs.filter(category__icontains=category)
        results = qs.values("brand").annotate(count=Count("id")).order_by("-count")[:limit]
        return [r["brand"] for r in results]
    except Exception:
        return []


def _update_preference_profile_from_feedback(
    user, products, feedback, query_context
):
    """Adjust UserPreferenceProfile based on message feedback."""
    from chat.models import UserPreferenceProfile

    profile, _ = UserPreferenceProfile.objects.get_or_create(user=user)
    weights = profile.attribute_weights or {}
    positive = feedback == "up"
    delta = POSITIVE_DELTA if positive else -NEGATIVE_DELTA

    categories = list({p.get("category", "").strip().lower() for p in products if p.get("category")})
    brands = list({p.get("brand", "").strip() for p in products if p.get("brand")})
    stores = list({p.get("store_slug", "").strip() for p in products if p.get("store_slug")})

    query_keys = list((query_context or {}).keys())
    for key in query_keys:
        if key in ("category", "brand", "color", "max_price", "min_price", "size",
                   "purpose", "gender", "material", "style", "occasion"):
            current = weights.get(key, 0.5)
            weights[key] = _clamp(current + delta)

    profile.attribute_weights = weights

    if positive:
        existing_brands = set(profile.preferred_brands or [])
        existing_cats = set(profile.preferred_categories or [])
        existing_stores = set(profile.preferred_stores or [])
        profile.preferred_brands = list(existing_brands | set(brands))[:20]
        profile.preferred_categories = list(existing_cats | set(categories))[:10]
        profile.preferred_stores = list(existing_stores | set(stores))[:10]
    else:
        # On negative feedback, remove brand/category if dismissal is persistent
        pass

    profile.save(update_fields=[
        "attribute_weights", "preferred_brands",
        "preferred_categories", "preferred_stores", "updated_at"
    ])


def _update_preference_profile_from_interaction(user, product, action):
    """Adjust preference profile based on product click/cart/purchase."""
    from chat.models import UserPreferenceProfile

    profile, _ = UserPreferenceProfile.objects.get_or_create(user=user)
    weights = profile.attribute_weights or {}

    delta = {
        "click": CLICK_DELTA,
        "add_cart": CART_DELTA,
        "purchase": CART_DELTA * 1.5
    }.get(action, CLICK_DELTA)

    category = (product.get("category") or "").strip().lower()
    brand = (product.get("brand") or "").strip()
    store_slug = (product.get("store_slug") or "").strip()

    if category:
        cats = set(profile.preferred_categories or [])
        cats.add(category)
        profile.preferred_categories = list(cats)[:10]
        weights["category"] = _clamp(weights.get("category", 0.5) + delta)

    if brand:
        brands = set(profile.preferred_brands or [])
        brands.add(brand)
        profile.preferred_brands = list(brands)[:20]
        weights["brand"] = _clamp(weights.get("brand", 0.5) + delta)

    if store_slug:
        stores = set(profile.preferred_stores or [])
        stores.add(store_slug)
        profile.preferred_stores = list(stores)[:10]

    profile.attribute_weights = weights
    profile.save(update_fields=[
        "attribute_weights", "preferred_brands",
        "preferred_categories", "preferred_stores", "updated_at"
    ])


def get_user_context_summary(user=None, session_key: str = "") -> dict:
    """
    Returns a dict of learned signals for a user/session.
    Merges personal preferences with collective platform signals.
    """
    from chat.models import UserPreferenceProfile, ProductInteraction

    summary = {
        "preferred_brands": [],
        "preferred_categories": [],
        "preferred_stores": [],
        "attribute_weights": {},
        "recent_positive_interactions": [],
        "recent_negative_interactions": [],
        "collective_popular_brands": [],
        "collective_popular_categories": [],
    }

    # ── Personal preferences for authenticated users ───────────────
    if user and user.is_authenticated:
        try:
            profile = UserPreferenceProfile.objects.get(user=user)
            summary["preferred_brands"] = profile.preferred_brands or []
            summary["preferred_categories"] = profile.preferred_categories or []
            summary["preferred_stores"] = profile.preferred_stores or []
            summary["attribute_weights"] = profile.attribute_weights or {}
        except UserPreferenceProfile.DoesNotExist:
            pass

    # ── Recent session interactions ────────────────────────────────
    qs = ProductInteraction.objects.none()
    if user and user.is_authenticated:
        qs = ProductInteraction.objects.filter(user=user).order_by("-created_at")[:30]
    elif session_key:
        qs = ProductInteraction.objects.filter(
            session_key=session_key
        ).order_by("-created_at")[:20]

    for interaction in qs:
        entry = {
            "name": interaction.product_name,
            "category": interaction.category,
            "brand": interaction.brand,
            "store": interaction.store_slug,
            "price": interaction.price,
        }
        if interaction.action in ("click", "add_cart", "purchase", "positive_feedback"):
            summary["recent_positive_interactions"].append(entry)
        elif interaction.action in ("dismiss", "negative_feedback"):
            summary["recent_negative_interactions"].append(entry)

    # ── Collective platform signals ────────────────────────────────
    try:
        summary["collective_popular_categories"] = get_collective_popular_categories(limit=5)
        # Get popular brands in the user's preferred categories
        if summary["preferred_categories"]:
            top_cat = summary["preferred_categories"][0]
            summary["collective_popular_brands"] = get_collective_popular_brands(
                category=top_cat, limit=6
            )
        else:
            summary["collective_popular_brands"] = get_collective_popular_brands(limit=6)
    except Exception:
        pass

    return summary