"""
偏好飞轮聚合（preference_aggregator）
扒自：Clover架构方案.md §偏好飞轮怎么转 + PRD §8
三层继承：L1 公司品牌基线 > L2 矩阵号人设（二期）> L3 个人手感
聚合最近 FLYWHEEL_LOOKBACK 条 events → prompt 片段注入文案生成

关键：
- 按 product_id 分开学（素颜霜偏好不串精华）
- 信号不足 FLYWHEEL_COLD_START 条时，用产品档案冷启动
- 返回结构对齐 API契约 GET /tasks/{id}/preference/context
"""
from __future__ import annotations
import logging
from collections import Counter
from typing import Any

from .constants import FLYWHEEL_LOOKBACK, FLYWHEEL_COLD_START

logger = logging.getLogger(__name__)


def aggregate_preference_context(
    events: list[dict],
    product: dict,
    workspace_id: int,
    product_id: int,
) -> dict:
    """
    输入：最近 preference_events 行（已按 workspace_id+product_id 过滤）
    输出：{recent_preference, reject_reasons, injected_count, prompt_fragment}
    prompt_fragment 直接注入文案生成 prompt
    """
    # 按 product_id 过滤（防串货）
    relevant = [
        e for e in events
        if e.get("workspace_id") == workspace_id and e.get("product_id") == product_id
    ][:FLYWHEEL_LOOKBACK]

    injected_count = len(relevant)

    if injected_count < FLYWHEEL_COLD_START:
        # 冷启动：用产品档案静态基线
        return _cold_start(product, injected_count)

    # ── 统计最常选角度（text_select + approve 信号）
    angle_counts: Counter = Counter()
    reject_reasons: list[str] = []

    for e in relevant:
        sig_type = e.get("signal_type", "")
        angle    = str(e.get("angle_label", "")).strip()
        weight   = int(e.get("signal_weight", 1))

        if sig_type in ("text_select", "approve") and angle:
            angle_counts[angle] += weight
        elif sig_type == "reject_with_reason":
            reason = str(e.get("reason", "")).strip()
            if reason:
                reject_reasons.append(reason)

    # 取权重最高的角度
    top_angles = [a for a, _ in angle_counts.most_common(3)]
    # 取最近3条打回原因
    recent_rejects = reject_reasons[-3:] if reject_reasons else []

    # ── 拼 prompt 片段（三层继承：L1>L2>L3，一期只跑L1+L3）
    prompt_fragment = _build_prompt_fragment(top_angles, recent_rejects, product)

    # ── 人类可读摘要（前端"本次已注入"显示）
    if top_angles:
        pref_summary = f"最近偏好角度：{'、'.join(top_angles)}（已选{injected_count}次信号）"
    else:
        pref_summary = f"已注入{injected_count}条偏好信号"

    return {
        "recent_preference": pref_summary,
        "reject_reasons": recent_rejects,
        "injected_count": injected_count,
        "prompt_fragment": prompt_fragment,   # 注入 generate_text_variants extra_rules
    }


def _cold_start(product: dict, injected_count: int) -> dict:
    """信号不足时用产品档案基线"""
    angles = product.get("text_angles") or []
    style  = product.get("style_tone", "素人分享风")
    fragment = ""
    if angles:
        fragment = f"优先覆盖以下文案角度：{'、'.join(angles[:3])}。风格调性：{style}。"
    return {
        "recent_preference": f"冷启动（历史信号{injected_count}条，不足{FLYWHEEL_COLD_START}条），使用产品档案基线",
        "reject_reasons": [],
        "injected_count": injected_count,
        "prompt_fragment": fragment,
    }


def _build_prompt_fragment(
    top_angles: list[str],
    reject_reasons: list[str],
    product: dict,
) -> str:
    """
    组装注入文案 prompt 的片段
    越积累越精准：1次=全靠基线；10次=知道偏好角度；30次=措辞从"供参考"升为明确指令
    """
    lines: list[str] = []
    if top_angles:
        lines.append(f"【偏好角度参考】历史选择偏好：{'、'.join(top_angles)}，请优先采用这些角度方向。")
    if reject_reasons:
        formatted = "；".join(f"「{r}」" for r in reject_reasons)
        lines.append(f"【打回原因参考】以下问题请主动规避：{formatted}。")
    # L1 品牌基线（产品档案 custom_prompt）
    custom = (product.get("custom_prompt") or "").strip()
    if custom:
        lines.append(f"【品牌基线】{custom}")
    return "\n".join(lines)


def collect_preference_event(
    signal_type: str,
    user_id: int,
    workspace_id: int,
    product_id: int,
    angle_label: str = "",
    reason: str = "",
    weights: dict[str, int] | None = None,
) -> dict:
    """
    构造 preference_event 行（由业务接口内部调用，不暴露给前端）
    返回待插 DB 的字段 dict
    """
    from .constants import FLYWHEEL_WEIGHTS
    w_map = weights or FLYWHEEL_WEIGHTS
    weight = w_map.get(signal_type, 0)
    return {
        "signal_type":   signal_type,
        "signal_weight": weight,
        "user_id":       user_id,
        "workspace_id":  workspace_id,
        "product_id":    product_id,
        "angle_label":   angle_label,
        "reason":        reason,
        "data_ownership": "client_data",  # 原始行为信号归客户（PRD §3 data_ownership）
    }
