"""
app/workers/replenish_task.py — 文案后台补充任务（S1: 先展示后台补铁律）

合格文案(passed且score>=90且非hard_block)不足用户目标条数时,
run_generation_pipeline 已先展示合格的; 此任务异步补齐到目标数或达上限。
只接收 task_id(基石B)。复用 pipeline_io.run_text_generation 的生成+过滤。
"""

import logging

from app.workers.celery_app import celery_app

logger = logging.getLogger(__name__)

# 补充上限：避免合格率低时无限补。最多补 MAX_REPLENISH_ROUNDS 轮。
MAX_REPLENISH_ROUNDS = 3


@celery_app.task(
    bind=True,
    name="app.workers.tasks.replenish_text_candidates",
    max_retries=2,
    default_retry_delay=30,
    queue="generation",
)
def replenish_text_candidates(self, task_id: int) -> dict:
    """后台补充合格文案到目标条数（或达补充上限）。

    每轮调用 run_text_generation 续生成,过滤后累加入库;
    已合格数 >= text_count 即停; 达 MAX_REPLENISH_ROUNDS 仍不足也停(不卡用户)。
    """
    from app.workers.tasks import _get_db, _push_event_sync
    from app.workers.pipeline_io import run_text_generation
    from app.workers.pipeline_steps import (
        load_task_and_product,
        decrypt_user_key,
        build_clients_and_clear_key,
        build_product_dict,
        load_flywheel_context,
    )
    from app.models.task import TextCandidate

    db = _get_db()
    try:
        task, product = load_task_and_product(db, task_id)
        if not task:
            logger.warning("补充任务找不到 task_id=%s", task_id)
            return {"task_id": task_id, "replenished": 0, "reason": "task_not_found"}

        # 已合格数（按入库的合格候选计）
        existing = db.query(TextCandidate).filter(
            TextCandidate.task_id == task_id
        ).count()
        target = task.text_count
        if existing >= target:
            return {"task_id": task_id, "replenished": 0, "reason": "already_enough"}

        workspace_id = task.workspace_id
        plain_key = decrypt_user_key(db, task.operator_id, workspace_id)
        clients = build_clients_and_clear_key(plain_key)
        plain_key = None  # 用完即清除，基石B
        product_dict = build_product_dict(product)
        flywheel_fragment, _ = load_flywheel_context(
            db, workspace_id, task.product_id, product_dict
        )

        seq = 9000  # 补充事件 seq 段，避开主流程
        rounds = 0
        # 真实入库合格数以 DB count 为准，绝不用 len(raw)(那是原始生成数含被过滤的低分条)。
        # task47 实测踩坑：len(raw)=2 但 saved=0(都没过90),误判达标提前停,库里仍缺。
        current = existing
        while current < target and rounds < MAX_REPLENISH_ROUNDS:
            rounds += 1
            run_text_generation(
                db, clients, task, product_dict, flywheel_fragment,
                _push_event_sync, workspace_id, seq,
            )
            # run_text_generation 内部已把本轮合格候选写库,这里重查真实库内条数
            db.expire_all()
            current = db.query(TextCandidate).filter(
                TextCandidate.task_id == task_id
            ).count()
            seq += 100
            logger.info(
                "补充轮 %d: task_id=%s 库内合格=%d/%d",
                rounds, task_id, current, target,
            )

        return {
            "task_id": task_id,
            "replenished": current - existing,
            "rounds": rounds,
            "final": current,
            "target": target,
        }
    except Exception as exc:
        logger.error("replenish_text_candidates failed: task_id=%s err=%s", task_id, exc)
        raise self.retry(exc=exc)
    finally:
        db.close()
