"""批量执行多关键词搜索并自动保存。"""
from __future__ import annotations

import json
from typing import Any

from agents.find_agent.support.batch_search_and_record import (
    _MAX_SEARCH_TASKS,
    _SOURCE_TYPES,
    _SUPPORTED_PROVIDERS,
    _load_result,
    _positive_page_limit,
)
from agents.find_agent.support.douyin_search import douyin_search
from agents.find_agent.support.douyin_search_tikhub import (
    DEFAULT_MIN_DURATION_SECONDS,
    douyin_search_tikhub,
)
from supply_agent.tools import tool


@tool
async def batch_search_and_record(
    run_id: str,
    searches: list[dict[str, Any]],
) -> str:
    """
    批量执行多个关键词搜索，并在每一页返回后立即保存搜索轨迹和候选视频。

    Args:
        run_id: 本次视频发现运行 id。
        searches: 搜索任务数组，最多 6 个。每项必须包含 keyword、query_reason、
            source_type；可包含 provider（internal_keyword / tikhub）、max_pages
            （1~2）、source_value、parent_search_id、content_type、sort_type、
            publish_time、filter_duration、min_duration_seconds。所有搜索源实际执行的
            min_duration_seconds 固定不低于 30。
    """
    run_text = str(run_id or "").strip()
    if not run_text:
        return json.dumps(
            {"error": "run_id 不能为空", "input_error": True},
            ensure_ascii=False,
        )
    if not isinstance(searches, list) or not searches:
        return json.dumps(
            {"error": "searches 必须是非空数组", "input_error": True},
            ensure_ascii=False,
        )
    if len(searches) > _MAX_SEARCH_TASKS:
        return json.dumps(
            {
                "error": f"searches 单次最多 {_MAX_SEARCH_TASKS} 个",
                "input_error": True,
            },
            ensure_ascii=False,
        )

    task_results: list[dict[str, Any]] = []
    total_pages = 0
    total_new_candidates = 0
    errors: list[str] = []

    for index, raw_task in enumerate(searches):
        if not isinstance(raw_task, dict):
            errors.append(f"[{index}] 搜索任务不是对象")
            continue

        keyword = str(raw_task.get("keyword") or "").strip()
        query_reason = str(raw_task.get("query_reason") or "").strip()
        source_type = str(raw_task.get("source_type") or "").strip()
        provider = str(raw_task.get("provider") or "internal_keyword").strip()
        if not keyword or not query_reason:
            errors.append(f"[{index}] keyword、query_reason 不能为空")
            continue
        if source_type not in _SOURCE_TYPES:
            errors.append(f"[{index}] source_type 不支持: {source_type}")
            continue
        if provider not in _SUPPORTED_PROVIDERS:
            errors.append(f"[{index}] provider 不支持: {provider}")
            continue

        max_pages = _positive_page_limit(raw_task.get("max_pages", 1))
        cursor: str | int = raw_task.get(
            "cursor",
            0 if provider == "tikhub" else "0",
        )
        provider_search_id = str(raw_task.get("search_id") or "")
        backtrace = str(raw_task.get("backtrace") or "")
        parent_search_id = raw_task.get("parent_search_id")
        page_results: list[dict[str, Any]] = []

        for page_no in range(1, max_pages + 1):
            common = {
                "run_id": run_text,
                "keyword": keyword,
                "query_reason": query_reason,
                "source_type": source_type,
                "source_value": raw_task.get("source_value"),
                "parent_search_id": parent_search_id,
                "page_no": page_no,
                "content_type": str(raw_task.get("content_type") or "视频"),
                "sort_type": str(raw_task.get("sort_type") or "综合排序"),
                "publish_time": str(raw_task.get("publish_time") or "不限"),
            }
            if provider == "tikhub":
                raw_result = await douyin_search_tikhub(
                    **common,
                    cursor=int(cursor or 0),
                    filter_duration=str(
                        raw_task.get("filter_duration") or "不限"
                    ),
                    search_id=provider_search_id,
                    backtrace=backtrace,
                    min_duration_seconds=int(
                        raw_task.get("min_duration_seconds")
                        or DEFAULT_MIN_DURATION_SECONDS
                    ),
                )
            else:
                raw_result = await douyin_search(
                    **common,
                    cursor=str(cursor or "0"),
                    min_duration_seconds=int(
                        raw_task.get("min_duration_seconds")
                        or DEFAULT_MIN_DURATION_SECONDS
                    ),
                )

            result = _load_result(raw_result)
            candidates = (
                result.get("candidates")
                if isinstance(result.get("candidates"), list)
                else []
            )
            page_results.append(
                {
                    "page_no": page_no,
                    "results_count": int(result.get("results_count") or 0),
                    "has_more": bool(result.get("has_more")),
                    "next_cursor": result.get("next_cursor"),
                    "search_id": result.get("search_id"),
                    "new_candidate_count": int(
                        result.get("new_candidate_count") or 0
                    ),
                    "candidates": candidates,
                    "persisted": bool(result.get("persisted")),
                    "error": result.get("error"),
                }
            )

            if result.get("persisted"):
                total_pages += 1
                total_new_candidates += int(
                    result.get("new_candidate_count") or 0
                )
            if result.get("error"):
                errors.append(
                    f"[{index}] {keyword} 第 {page_no} 页: {result['error']}"
                )
                break
            if not result.get("has_more") or page_no >= max_pages:
                break

            cursor = result.get("next_cursor") or cursor
            provider_search_id = str(
                result.get("provider_search_id") or provider_search_id
            )
            backtrace = str(result.get("backtrace") or backtrace)
            parent_search_id = result.get("search_id") or parent_search_id

        task_results.append(
            {
                "index": index,
                "keyword": keyword,
                "provider": provider,
                "pages": page_results,
            }
        )

    payload = {
        "title": "批量搜索并自动落库",
        "run_id": run_text,
        "task_count": len(task_results),
        "saved_page_count": total_pages,
        "new_candidate_count": total_new_candidates,
        "error_count": len(errors),
        "errors": errors,
        "tasks": task_results,
        "output": (
            f"完成 {len(task_results)} 个搜索任务，保存 {total_pages} 页，"
            f"新增候选 {total_new_candidates} 条，错误 {len(errors)} 个"
        ),
    }
    if errors and not total_pages:
        payload["error"] = "批量搜索没有成功保存任何搜索页"
    return json.dumps(payload, ensure_ascii=False)
