"""Strategy workbench routes — V2 contract.

契约路径见 ``core/ui/fed/src/pages/strategyWorkbenchPage/API.md``；
编排说明见 ``ROUTES_ORCHESTRATION.md``。
应用挂载前缀：``/api``（见 ``core/ui/bff/app.py``）。

工作台实现栈在 ``strategy_stack`` 中首次请求时再 import，避免 BFF 启动即拉 DataManager 等。
"""

from flask import Blueprint, request

from core.ui.bff.shared.response import error, ok

from .formatting import workbench_snapshot_to_message
from .helpers import json_payload, pagination_params
from .strategy_stack import get_strategy_workbench_stack

strategy_workbench_api_bp = Blueprint("strategy_workbench_api", __name__)


# --- V2-01 ---
@strategy_workbench_api_bp.route(
    "/v1/strategy/<strategy_name>/version/latest",
    methods=["GET"],
)
def get_strategy_version_latest(strategy_name):
    s = get_strategy_workbench_stack()
    row = s.fetch_latest_workbench_snapshot(strategy_name)
    if row is None:
        return error("策略不存在或无法加载工作台数据", 404)
    msg = workbench_snapshot_to_message(row)
    msg.update(s.workbench_latest_ui_flags(strategy_name, row))
    return ok(msg)


# --- V2-02 ---
@strategy_workbench_api_bp.route("/v1/strategies/list", methods=["GET"])
def get_strategies_list():
    s = get_strategy_workbench_stack()
    page, limit = pagination_params()
    items, total = s.fetch_discovered_strategies_page(page, limit)
    return ok({"items": items, "total": total, "page": page, "limit": limit})


# --- V2-03 ---
@strategy_workbench_api_bp.route(
    "/v1/strategy/<strategy_name>/versions",
    methods=["GET"],
)
def get_strategy_versions(strategy_name):
    """GET /strategy/{strategy_name}/versions — 下拉 / 版本对比，至多 10 条。"""
    s = get_strategy_workbench_stack()
    items = s.fetch_strategy_versions_dropdown(strategy_name)
    return ok({"items": items})


# --- V2-04（选项类：固定子路径，见 API.md） ---
@strategy_workbench_api_bp.route(
    "/v1/strategy/settings/capital-allocation-strategies",
    methods=["GET"],
)
def get_settings_capital_allocation_strategies():
    """GET /strategy/settings/capital-allocation-strategies"""
    s = get_strategy_workbench_stack()
    return ok({"items": s.items_capital_allocation_strategies()})


@strategy_workbench_api_bp.route(
    "/v1/strategy/settings/sampling-strategies",
    methods=["GET"],
)
def get_settings_sampling_strategies():
    """GET /strategy/settings/sampling-strategies"""
    s = get_strategy_workbench_stack()
    return ok({"items": s.items_sampling_strategies()})


@strategy_workbench_api_bp.route(
    "/v1/strategy/settings/simulation-templates",
    methods=["GET"],
)
def get_settings_simulation_templates():
    """GET /strategy/settings/simulation-templates"""
    s = get_strategy_workbench_stack()
    return ok({"items": s.items_simulation_templates()})


# --- V2-05 ---
@strategy_workbench_api_bp.route(
    "/v1/strategy/<strategy_name>/<step>/run",
    methods=["POST"],
)
def post_strategy_step_run(strategy_name, step):
    """POST /strategy/{strategy_name}/{step}/run — 成功时务必携带返回的 ``job_id`` 轮询 progress。"""
    s = get_strategy_workbench_stack()
    payload = json_payload()
    settings = payload.get("settings")
    if settings is None or not isinstance(settings, dict):
        return error("settings 必须为对象", 400)

    body_name = payload.get("strategy_name")
    if body_name is not None and str(body_name).strip() != str(strategy_name).strip():
        return error("strategy_name 与路径不一致", 400)

    raw_force = payload.get("is_force", False)
    is_force = raw_force if isinstance(raw_force, bool) else bool(raw_force)

    out = s.submit_workbench_step_via_bff_contract(
        strategy_name=strategy_name,
        step=step,
        api_settings=settings,
        is_force=is_force,
    )
    if out.get("is_triggered"):
        return ok(
            {
                "is_triggered": True,
                "job_id": out["job_id"],
                "run_id": out.get("run_id") or out["job_id"],
                "steps": out.get("steps") or [],
            }
        )
    return ok({"is_triggered": False, "reason": out.get("reason", "未知错误")})


# --- V2-06b：整次 run 编排进度（``steps[]``，不依赖路径 ``step``） ---
@strategy_workbench_api_bp.route(
    "/v1/strategy/<strategy_name>/run/progress",
    methods=["GET"],
)
def get_strategy_run_progress(strategy_name):
    s = get_strategy_workbench_stack()
    q_job = (request.args.get("job_id") or "").strip()
    if not q_job:
        return error("缺少必填 query 参数 job_id", 400)
    payload = s.get_run_progress(
        strategy_name=str(strategy_name),
        job_id=q_job,
    )
    if payload is None:
        return error("未找到该 job 的编排进度", 404)
    return ok(payload)


# --- V2-06 ---
@strategy_workbench_api_bp.route(
    "/v1/strategy/<strategy_name>/<step>/progress",
    methods=["GET"],
)
def get_strategy_step_progress(strategy_name, step):
    """GET /strategy/{strategy_name}/{step}/progress — **必填** query ``job_id``（与 V2-05 返回一致）。"""
    s = get_strategy_workbench_stack()
    norm = s.normalize_step(step)
    if norm is None:
        return error("step 须为 enum / price / capital", 400)
    q_job = (request.args.get("job_id") or "").strip()
    if not q_job:
        return error("缺少必填 query 参数 job_id", 400)
    payload = s.get_step_progress(
        strategy_name=strategy_name,
        normalized_step=norm,
        job_id=q_job,
    )
    if payload is None:
        return error("任务不存在或与路径不匹配", 404)
    return ok(payload)


# --- V2-07（report：路径 ``version_id``；典型来源为 V2-06 completed 响应） ---
@strategy_workbench_api_bp.route(
    "/v1/strategy/<strategy_name>/<step>/report/<version_id>",
    methods=["GET"],
)
def get_strategy_step_report(strategy_name, step, version_id):
    """
    GET …/report/<version_id>

    **路径** ``version_id``（``v3`` / ``3``）。本轮 run 在 **V2-06** 达 **completed**
    且 ``snapshot_id>0`` 时已下发 ``version_id``，前端用同一值拉取该步明细；历史/对比亦为同一参数。
    """
    s = get_strategy_workbench_stack()
    norm = s.normalize_step(step)
    if norm is None:
        return error("step 须为 enum / price / capital", 400)

    path_vid = str(version_id or "").strip()
    if not path_vid:
        return error("缺少路径参数 version_id", 400)

    sid = s.parse_snapshot_id(path_vid)
    if sid is None:
        return error("version_id 无效", 400)
    msg = s.build_step_report_message(
        strategy_name=strategy_name,
        normalized_step=norm,
        snapshot_id=sid,
    )
    if msg is None:
        return error("快照不存在", 404)
    return ok(msg)


# --- V2-07b：枚举逐股 ref（``0_stock_ref.json``） ---
@strategy_workbench_api_bp.route(
    "/v1/strategy/<strategy_name>/<step>/report_ref/<version_id>",
    methods=["GET"],
)
def get_strategy_step_report_ref(strategy_name, step, version_id):
    """GET …/report_ref/<version_id> — 仅 ``enum`` 步；``stock_ref`` 可空（磁盘清理属正常；见 ``stock_ref_available``）。"""
    s = get_strategy_workbench_stack()
    norm = s.normalize_step(step)
    if norm is None:
        return error("step 须为 enum / price / capital", 400)

    path_vid = str(version_id or "").strip()
    if not path_vid:
        return error("缺少路径参数 version_id", 400)

    sid = s.parse_snapshot_id(path_vid)
    if sid is None:
        return error("version_id 无效", 400)
    msg = s.build_step_report_ref_message(
        strategy_name=strategy_name,
        normalized_step=norm,
        snapshot_id=sid,
    )
    if msg is None:
        return error("快照不存在", 404)
    return ok(msg)


# --- V2-08 ---
@strategy_workbench_api_bp.route(
    "/v1/strategy/<strategy_name>/version/<version_id>",
    methods=["GET"],
)
def get_strategy_version_snapshot(strategy_name, version_id):
    """GET /strategy/{strategy_name}/version/{version_id} — 与 latest 同形，按 id 取行（无冷启动）。"""
    s = get_strategy_workbench_stack()
    sid = s.parse_snapshot_id(version_id)
    if sid is None:
        return error("version_id 无效", 400)
    row = s.fetch_workbench_snapshot_by_snapshot_id(strategy_name, sid)
    if row is None:
        return error("快照不存在", 404)
    return ok(workbench_snapshot_to_message(row))


# --- V2-09 ---
@strategy_workbench_api_bp.route(
    "/v1/strategy/<strategy_name>/apply-settings/<version_id>",
    methods=["POST"],
)
def post_apply_settings(strategy_name, version_id):
    """POST /strategy/{strategy_name}/apply-settings/{version_id} — 快照 settings → userspace ``settings.py``。"""
    s = get_strategy_workbench_stack()
    sid = s.parse_snapshot_id(version_id)
    if sid is None:
        return error("version_id 无效", 400)

    payload = json_payload()
    raw_pretty = payload.get("pretty", False) if isinstance(payload, dict) else False
    pretty = raw_pretty if isinstance(raw_pretty, bool) else bool(raw_pretty)

    out, err = s.apply_workbench_snapshot_settings_to_userspace(
        strategy_name=strategy_name,
        snapshot_id=sid,
        pretty=pretty,
    )
    if err:
        if err == "快照不存在":
            return error(err, 404)
        if err == "存储不可用":
            return error(err, 503)
        if err.startswith("写盘失败") or err.startswith("更新快照时间失败"):
            return error(err, 500)
        return error(err, 400)
    return ok(out)
