"""
prompt_composer.py — 统一 prompt 组装入口（≤100行）
扒自：banana prompts/service.py + worker/src/copy.js prompt 逻辑
Lead 指名接口：compose_variants / compose_preference_context

组装逻辑委托：
  _text_prompt.py → build_prompt (文案 prompt 主体)
  preference_aggregator.py → aggregate_preference_context (飞轮上下文)

原则：prompt 组装从这里进，不散落在 text_variants / generate_text_variants 里。
"""
from __future__ import annotations
import logging
from typing import Any

from ._text_prompt import build_prompt, COPY_SYSTEM
from .preference_aggregator import aggregate_preference_context

logger = logging.getLogger(__name__)


# ── 主接口 ────────────────────────────────────────────────────────────────────

def compose_variants(
    product: dict,
    count: int,
    flywheel_context: str = "",
    extra_rules: str = "",
) -> tuple[str, str]:
    """
    一次出 count 角度文案的完整 prompt。

    返回 (system_prompt, user_prompt)。
    飞轮片段追加到 user_prompt 末尾（不改 system，避免覆盖质量红线）。

    参数：
      product         — 产品档案 dict（name/selling_points/text_angles/custom_prompt 等）
      count           — 需要几条
      flywheel_context— 由 compose_preference_context 返回的 prompt_fragment
      extra_rules     — 额外规则（优化循环重生成时传 hint）
    """
    combined_extra = "\n".join(filter(None, [flywheel_context, extra_rules]))
    user_prompt = build_prompt(product, count, extra_rules=combined_extra)
    logger.debug(
        "compose_variants: product=%s count=%d flywheel_len=%d",
        product.get("name", "?"), count, len(flywheel_context),
    )
    return COPY_SYSTEM, user_prompt


def compose_preference_context(
    events: list[dict],
    product: dict,
    workspace_id: int,
    product_id: int,
) -> dict:
    """
    聚合偏好事件 → 可注入 prompt 的飞轮上下文。

    返回结构（对齐 API契约 GET /tasks/{id}/preference/context）：
      {
        recent_preference: str,   # 人类可读摘要（前端"本次已注入"显示）
        reject_reasons:    list,  # 最近打回原因
        injected_count:    int,   # 有效信号数
        prompt_fragment:   str,   # 注入 compose_variants flywheel_context 的字符串
      }

    信号不足 FLYWHEEL_COLD_START 条时用产品档案冷启动。
    按 workspace_id + product_id 双维过滤（素颜霜偏好不串精华）。
    """
    return aggregate_preference_context(events, product, workspace_id, product_id)


# ── 辅助：解析模型返回的 JSON（给 text_variants 调用，集中不散） ──────────────

def parse_model_output(raw: str) -> list[dict]:
    """从 LLM 原始输出提取 JSON 数组（容错 markdown 包裹）"""
    from ._text_prompt import parse_json_array
    return parse_json_array(raw)


# ── 辅助：图片 prompt 组装入口（预留，联调时填充）─────────────────────────────

def compose_image_prompt(
    role_name: str,
    visual_system: dict,
    product: dict,
    extra: str = "",
) -> str:
    """
    单张分镜 prompt 组装（供 image_gen.generate_one_image 调用）。
    TODO: 联调后从 storyboard.plan_image_set 取 base_prompt 注入。

    role_name    — 分镜角色（hook / pain_scene / closer 等）
    visual_system— build_visual_system 返回的视觉系统 dict
    extra        — 追加约束（飞轮图片偏好片段，二期接入）
    """
    name    = product.get("name", "产品")
    style   = visual_system.get("style", "")
    palette = visual_system.get("color_palette", "")
    base    = visual_system.get("base_prompt", "")
    lines = [
        f"[{role_name}] 为产品「{name}」生成种草图。",
        base and f"视觉基调：{base}",
        style and f"摄影风格：{style}",
        palette and f"色调：{palette}",
        extra,
    ]
    return "\n".join(l for l in lines if l)
