"""动态策略：以 yaml 静态种子为基础，叠加动态种子（统一池 + 加权随机 + 用完全用）。

种子词机制（v49 起）：
1. 全部类型放一起（统一池）：静态 style + 静态 related + 月份主题 + 节日 + LLM 动态
   ——合并去重（跨类型同词只保留一个，权重累加 = 多来源更受重视）；
2. 节日种子词提供权重：节日权重 3.0 > 月份主题 2.0 > 静态/动态 1.0，随机抽取时加权；
3. 每次随机取：从池中按权重随机抽取（不重复），limit 内数量；
4. 用完全用：池中种子数 ≤ 需要数时全部使用（不再随机限量/截断）；
5. 每个国家独立配置：configs/countries/<country>.yaml 的 style.seeds / related.seed_keywords。

limit 由 seed_node 从 context 注入：max_seeds（单一总量，不再按类型分，从统一池随机抽后均分
style/related）；兼容旧参数 max_style_seeds / max_related_seeds（0 或缺失=不限）。
LLM 后端生成失败时自动回退到静态+节日主题，保证不中断。
"""
import random
from typing import Any, Dict, List

from .base import SeedStrategy


def _weighted_sample(pool: List[Dict[str, Any]], k: int) -> List[Dict[str, Any]]:
    """按权重随机不重复取 k 个；池数量 ≤ k（或用完）时全部返回（不随机限量）。"""
    if k <= 0 or len(pool) <= k:
        return list(pool)
    out: List[Dict[str, Any]] = []
    rest = list(pool)
    for _ in range(k):
        weights = [max(float(it["weight"]), 0.0) for it in rest]
        if sum(weights) <= 0:
            out.extend(rest)
            break
        idx = random.choices(range(len(rest)), weights=weights)[0]
        out.append(rest.pop(idx))
    return out


class DynamicStrategy(SeedStrategy):
    name = "dynamic"

    def resolve(
        self,
        country: str,
        cc: Dict[str, Any],
        context: Dict[str, Any],
        llm_backend: Any = None,
    ) -> Dict[str, Any]:
        base_style = list((cc.get("style", {}) or {}).get("seeds", []) or [])
        base_related = list((cc.get("related", {}) or {}).get("seed_keywords", []) or [])
        month_style = list(context.get("month_themes", []) or [])
        holidays = list(context.get("upcoming_holidays", []) or [])
        holiday_style = [f"{h.lower()} aesthetic" for h in holidays]
        # 节日主题同时扩充 related 源（提高节日权重 + 增加 related 扩展）
        holiday_related = [f"{h.lower()} tee" if not h.lower().endswith("day") else f"{h.lower()} gift"
                           for h in holidays]

        # LLM 动态种子（失败回退，不影响静态/节日）
        dyn_style: List[str] = []
        dyn_related: List[str] = []
        if llm_backend is not None and hasattr(llm_backend, "generate_seeds"):
            try:
                res = llm_backend.generate_seeds(context) or {}
                dyn_style = list(res.get("style_seeds", []) or [])
                dyn_related = list(res.get("related_seeds", []) or [])
            except Exception as e:  # noqa: BLE001
                print(f"[seed] LLM 生成种子失败，仅用静态+节日主题: {e}")

        # 1) 统一池：全部类型合并，跨类型去重（同词权重累加 = 多来源更受重视）
        pool: Dict[str, Dict[str, Any]] = {}

        def add(items: List[str], weight: float, src: str) -> None:
            for it in items:
                it = (it or "").strip()
                if not it:
                    continue
                key = it.lower()
                if key in pool:
                    pool[key]["weight"] += weight
                    pool[key]["sources"].append(src)
                else:
                    pool[key] = {"word": it, "weight": weight, "sources": [src]}

        add(base_style, 1.0, "static")
        add(base_related, 1.0, "static")
        add(month_style, 2.0, "month")
        add(holiday_style, 3.0, "holiday")
        add(holiday_related, 3.0, "holiday")
        add(dyn_style, 1.0, "dynamic")
        add(dyn_related, 1.0, "dynamic")

        items = list(pool.values())
        limit_total = int(context.get("max_seeds") or 0)
        limit_style = int(context.get("max_style_seeds") or 0)
        limit_related = int(context.get("max_related_seeds") or 0)

        if limit_total > 0:
            # 不再按类型分：从统一池随机抽 max_seeds 个，均分到 style/related（各约一半）
            pick = _weighted_sample(items, limit_total)
            half = (len(pick) + 1) // 2
            style_pick = pick[:half]
            related_pick = pick[half:]
        else:
            # 兼容旧参数（max_style_seeds / max_related_seeds 分别限量）
            style_pick = _weighted_sample(items, limit_style)
            style_keys = {id(it) for it in style_pick}
            remaining = [it for it in items if id(it) not in style_keys]
            related_pick = _weighted_sample(remaining, limit_related)

        return {
            "style_seeds": [it["word"] for it in style_pick],
            "related_seeds": [it["word"] for it in related_pick],
            "dynamic": True,
            "pool_size": len(items),
            "pool": [it["word"] for it in items],
            "llm_style_seeds": dyn_style,
            "llm_related_seeds": dyn_related,
            "holiday_style_seeds": holiday_style,
            "holiday_related_seeds": holiday_related,
            "static_style_seeds": base_style,
            "static_related_seeds": base_related,
        }
