"""多智能体模式 server 路由。

- `/multiagent/new` 返回主 SPA 入口（与 `/new` 一样返回 static/index.html）
  前端通过路径识别多智能体模式后，在创建对话时写入 metadata.multi_agent_mode=true
- `/api/multiagent/conversations` POST 创建多智能体对话（写入 metadata）
- `/api/multiagent/roles` GET 列出可用角色
- `/api/multiagent/roles` POST 创建自定义角色
"""
from __future__ import annotations

from pathlib import Path
from typing import Any, Dict, List

from flask import Blueprint, current_app, jsonify, request, session

from server.auth_helpers import api_login_required, login_required, get_current_username
from server.context import get_user_resources
from modules.multi_agent.role_store import (
    RoleConfig,
    list_roles,
    load_preset_role,
    save_custom_role,
    delete_custom_role,
    is_preset_role,
    sync_preset_roles,
)
from config.paths import CUSTOM_ROLES_DIR, WEB_PRESET_ROLES_DIR

multi_agent_bp = Blueprint("multi_agent", __name__)


@multi_agent_bp.route("/multiagent/new")
@login_required
def multi_agent_new_page():
    """多智能体模式入口，返回与 /new 相同的 SPA index.html。"""
    return current_app.send_static_file("index.html")


@multi_agent_bp.route("/multiagent/<path:conversation_id>")
@login_required
def multi_agent_conversation_page(conversation_id: str):
    """多智能体模式 指定会话 URL，返回 SPA index.html 让前端路由处理。"""
    return current_app.send_static_file("index.html")


@multi_agent_bp.route("/api/multiagent/rebuild-index", methods=["POST"])
@api_login_required
def rebuild_conversation_index_api():
    """强制从磁盘重建对话索引，补全 multi_agent_mode 等新字段。"""
    try:
        username = get_current_username()
        if not username:
            return jsonify({"success": False, "error": "未登录"}), 401
        terminal, _ = get_user_resources(username)
        if not terminal:
            return jsonify({"success": False, "error": "工作区未就绪"}), 503
        ctx_manager = getattr(terminal, "context_manager", None)
        if not ctx_manager:
            return jsonify({"success": False, "error": "上下文管理器未初始化"}), 503
        ma_manager = getattr(ctx_manager, "multi_agent_conversation_manager", None)
        if not ma_manager:
            return jsonify({"success": False, "error": "多智能体对话管理器未初始化"}), 503
        rebuilt = ma_manager._rebuild_index_from_files()
        ma_manager._save_index(rebuilt)
        return jsonify({"success": True, "index_size": len(rebuilt)})
    except Exception as exc:
        return jsonify({"success": False, "error": str(exc)}), 500


def _get_role_dirs() -> tuple:
    """根据 session 判断当前登录模式，返回 (runtime_dir, custom_dir)。

    - host 模式：runtime_dir = custom_dir = host/mutiagents/agents
    - web/docker 模式：runtime_dir = web/mutiagents/agents, custom_dir = users/<user>/personal/mutiagents/agents
    """
    from flask import session as _session
    is_host_session = bool(_session.get('host_mode'))
    if is_host_session:
        return CUSTOM_ROLES_DIR, CUSTOM_ROLES_DIR
    # web 模式
    username = get_current_username()
    if not username:
        return WEB_PRESET_ROLES_DIR, None
    _, workspace = get_user_resources(username)
    if not workspace or not workspace.data_dir:
        return WEB_PRESET_ROLES_DIR, None
    from modules.multi_agent.role_store import infer_custom_roles_dir
    custom = infer_custom_roles_dir(workspace.data_dir)
    return WEB_PRESET_ROLES_DIR, str(custom) if custom else None


@multi_agent_bp.route("/api/multiagent/roles", methods=["GET"])
@api_login_required
def list_roles_api():
    """列出全部可用角色（预置+用户自定义）。"""
    try:
        runtime_dir, custom_dir = _get_role_dirs()
        roles = list_roles(runtime_dir=runtime_dir, custom_dir=custom_dir)
        return jsonify({
            "success": True,
            "roles": [r.to_dict() for r in roles],
        })
    except Exception as exc:
        return jsonify({"success": False, "error": str(exc)}), 500


@multi_agent_bp.route("/api/multiagent/roles", methods=["POST"])
@api_login_required
def create_role_api():
    """创建自定义角色。body: { role_id, name, description?, body_prompt, thinking_mode? }"""
    try:
        data = request.get_json() or {}
        role_id = str(data.get("role_id") or "").strip()
        name = str(data.get("name") or "").strip()
        body_prompt = str(data.get("body_prompt") or "").strip()
        description = str(data.get("description") or "").strip()
        thinking_mode = str(data.get("thinking_mode") or "fast").strip()
        model_key = str(data.get("model_key") or "").strip() or None
        if not role_id or not name or not body_prompt:
            return jsonify({"success": False, "error": "role_id/name/body_prompt 必填"}), 400
        if thinking_mode not in {"fast", "thinking"}:
            thinking_mode = "fast"
        # 不允许覆盖预设角色
        if is_preset_role(role_id):
            return jsonify({"success": False, "error": f"不能覆盖预设角色 {role_id}"}), 409
        # 不允许覆盖已存在的用户自定义角色
        runtime_dir, custom_dir = _get_role_dirs()
        existing = {r.role_id for r in list_roles(runtime_dir=runtime_dir, custom_dir=custom_dir)}
        if role_id in existing:
            return jsonify({"success": False, "error": f"角色 {role_id} 已存在"}), 409
        role = RoleConfig(
            role_id=role_id,
            name=name,
            description=description,
            body_prompt=body_prompt,
            thinking_mode=thinking_mode,
            model_key=model_key,
            is_custom=True,
        )
        saved = save_custom_role(role, custom_dir=custom_dir)
        return jsonify({"success": True, "role_id": role_id, "file": str(saved)})
    except Exception as exc:
        return jsonify({"success": False, "error": str(exc)}), 500


@multi_agent_bp.route("/api/multiagent/roles/<role_id>", methods=["PUT"])
@api_login_required
def update_role_api(role_id: str):
    """更新用户自定义角色。不能更新预设角色。"""
    try:
        data = request.get_json() or {}
        runtime_dir, custom_dir = _get_role_dirs()
        # 加载现有角色（先查自定义覆盖，再查预设）
        role = load_preset_role(role_id, runtime_dir=runtime_dir, custom_dir=custom_dir)
        if not role:
            return jsonify({"success": False, "error": f"角色 {role_id} 不存在"}), 404
        # 更新字段
        if "name" in data:
            role.name = str(data["name"]).strip() or role.name
        if "description" in data:
            role.description = str(data["description"] or "").strip()
        if "body_prompt" in data:
            role.body_prompt = str(data["body_prompt"] or "").strip()
        if "thinking_mode" in data:
            tm = str(data["thinking_mode"] or "fast").strip()
            if tm in {"fast", "thinking"}:
                role.thinking_mode = tm
        if "model_key" in data:
            role.model_key = str(data["model_key"] or "").strip() or None
        if "skills" in data:
            role.skills = list(data["skills"] or [])
        role.is_custom = True
        saved = save_custom_role(role, custom_dir=custom_dir)
        return jsonify({"success": True, "role_id": role_id, "file": str(saved)})
    except Exception as exc:
        return jsonify({"success": False, "error": str(exc)}), 500


@multi_agent_bp.route("/api/multiagent/roles/<role_id>", methods=["DELETE"])
@api_login_required
def delete_role_api(role_id: str):
    """删除用户自定义角色。不能删除预设角色。"""
    try:
        if is_preset_role(role_id):
            return jsonify({"success": False, "error": f"不能删除预设角色 {role_id}"}), 403
        _, custom_dir = _get_role_dirs()
        deleted = delete_custom_role(role_id, custom_dir=custom_dir)
        if not deleted:
            return jsonify({"success": False, "error": f"角色 {role_id} 不存在或无法删除"}), 404
        return jsonify({"success": True, "role_id": role_id})
    except Exception as exc:
        return jsonify({"success": False, "error": str(exc)}), 500


@multi_agent_bp.route("/api/multiagent/settings", methods=["GET"])
@api_login_required
def get_multi_agent_settings_api():
    """获取多智能体模式设置（子智能体压缩阈值等）。"""
    try:
        username = get_current_username()
        if not username:
            return jsonify({"success": False, "error": "未登录"}), 401
        _, workspace = get_user_resources(username)
        if not workspace:
            return jsonify({"success": False, "error": "工作区未就绪"}), 503
        # 从个人化配置中读取子智能体压缩阈值
        from modules.personalization_manager import load_personalization_config
        prefs = load_personalization_config(workspace.data_dir) or {}
        compress_threshold = prefs.get("sub_agent_compress_threshold_tokens", 150000)
        return jsonify({
            "success": True,
            "settings": {
                "sub_agent_compress_threshold_tokens": compress_threshold,
            },
        })
    except Exception as exc:
        return jsonify({"success": False, "error": str(exc)}), 500


@multi_agent_bp.route("/api/multiagent/settings", methods=["PUT"])
@api_login_required
def update_multi_agent_settings_api():
    """更新多智能体模式设置。"""
    try:
        username = get_current_username()
        if not username:
            return jsonify({"success": False, "error": "未登录"}), 401
        _, workspace = get_user_resources(username)
        if not workspace:
            return jsonify({"success": False, "error": "工作区未就绪"}), 503
        data = request.get_json() or {}
        settings = data.get("settings") or {}
        # 更新子智能体压缩阈值
        threshold = settings.get("sub_agent_compress_threshold_tokens")
        if threshold is not None:
            threshold = int(threshold)
            if threshold < 10000:
                return jsonify({"success": False, "error": "压缩阈值不能小于 10000"}), 400
            from modules.personalization_manager import load_personalization_config, save_personalization_config
            prefs = load_personalization_config(workspace.data_dir) or {}
            prefs["sub_agent_compress_threshold_tokens"] = threshold
            save_personalization_config(workspace.data_dir, prefs)
        return jsonify({"success": True})
    except Exception as exc:
        return jsonify({"success": False, "error": str(exc)}), 500


@multi_agent_bp.route("/api/multiagent/conversations", methods=["POST"])
@api_login_required
def create_multi_agent_conversation():
    """创建多智能体模式对话。在 metadata 中写入 multi_agent_mode=true。

    body: { workspace_id?, thinking_mode?, run_mode?, preserve_mode? }
    """
    import time as _time
    from server.conversation import _get_active_workspace_task, _resolve_target_terminal_for_workspace
    from modules.personalization_manager import load_personalization_config
    try:
        from server.user_workspace import UserWorkspace  # noqa
    except Exception:
        UserWorkspace = None  # type: ignore

    username = get_current_username()
    if not username:
        return jsonify({"success": False, "error": "未登录"}), 401

    data = request.get_json() or {}
    target_workspace_id = (data.get("workspace_id") or "").strip()

    terminal, workspace = get_user_resources(username)
    if not terminal or not workspace:
        return jsonify({"success": False, "error": "工作区未就绪"}), 503

    if target_workspace_id:
        try:
            terminal, workspace = _resolve_target_terminal_for_workspace(
                username, target_workspace_id, terminal, workspace
            )
        except ValueError as exc:
            return jsonify({"success": False, "error": str(exc)}), 404
        except RuntimeError as exc:
            return jsonify({"success": False, "error": str(exc)}), 503

    preserve_mode = bool(data.get("preserve_mode"))
    thinking_mode = data.get("thinking_mode") if preserve_mode and "thinking_mode" in data else None
    run_mode = data.get("mode") if preserve_mode and "mode" in data else None

    effective_workspace_id = target_workspace_id or session.get("workspace_id") or "default"
    active_task = _get_active_workspace_task(username=username, workspace_id=effective_workspace_id)

    try:
        prefs = load_personalization_config(workspace.data_dir)
    except Exception:
        prefs = {}

    ctx_manager = getattr(terminal, "context_manager", None)
    if not ctx_manager:
        return jsonify({"success": False, "error": "上下文管理器未初始化"}), 500
    cm = getattr(ctx_manager, "multi_agent_conversation_manager", None) or getattr(ctx_manager, "conversation_manager", None)
    if not cm:
        return jsonify({"success": False, "error": "对话管理器未初始化"}), 500

    safe_run_mode = run_mode
    if safe_run_mode not in {"fast", "thinking", "deep"}:
        candidate = (prefs or {}).get("default_run_mode")
        safe_run_mode = candidate if candidate in {"fast", "thinking", "deep"} else "fast"
    safe_thinking = bool(thinking_mode) if thinking_mode is not None else safe_run_mode != "fast"
    default_permission_mode = (prefs or {}).get("default_permission_mode")
    if default_permission_mode not in ("readonly", "approval", "auto_approval", "unrestricted"):
        default_permission_mode = None

    previous_cm_current = getattr(ctx_manager, "current_conversation_id", None)

    conversation_id = cm.create_conversation(
        project_path=str(workspace.project_path),
        thinking_mode=safe_thinking,
        run_mode=safe_run_mode,
        initial_messages=[],
        model_key=(prefs or {}).get("default_model") or getattr(terminal, "model_key", None),
        metadata_overrides={
            "permission_mode": default_permission_mode or getattr(terminal, "get_permission_mode", lambda: "unrestricted")(),
            "execution_mode": getattr(terminal, "get_execution_mode", lambda: "sandbox")(),
            "multi_agent_mode": True,
        },
    )
    # 恢复 context_manager 的当前对话（不要影响普通对话的 current_conversation_id）
    try:
        ctx_manager.current_conversation_id = previous_cm_current
    except Exception:
        pass

    # 触发对话列表更新事件
    try:
        from server.app_legacy import socketio
        socketio.emit('conversation_list_update', {
            'action': 'created',
            'conversation_id': conversation_id,
        }, room=f"user_{username}")
    except Exception:
        pass

    return jsonify({
        "success": True,
        "conversation_id": conversation_id,
        "multi_agent_mode": True,
    }), 201


@multi_agent_bp.route("/api/multiagent/models", methods=["GET"])
@api_login_required
def list_sub_agent_models_api():
    """列出子智能体可用的模型列表（从 sub_agent_models.json 读取，脱敏后返回）。"""
    try:
        from config.sub_agent import SUB_AGENT_MODELS_CONFIG_FILE
        from pathlib import Path as _Path
        import json as _json
        config_path = SUB_AGENT_MODELS_CONFIG_FILE
        if not _Path(config_path).exists():
            return jsonify({"success": True, "models": [], "default_model": ""})
        raw = _json.loads(_Path(config_path).read_text(encoding="utf-8"))
        models_raw = raw.get("models", []) if isinstance(raw, dict) else (raw if isinstance(raw, list) else [])
        default_model = str(raw.get("default_model", "")) if isinstance(raw, dict) else ""
        # 脱敏：只返回 name / modes / multimodal / max_output / max_context
        safe_models = []
        for m in models_raw:
            if not isinstance(m, dict):
                continue
            safe_models.append({
                "name": m.get("name") or m.get("model_name") or "",
                "modes": m.get("modes") or m.get("mode") or "",
                "multimodal": m.get("multimodal") or "none",
                "max_output": m.get("max_output") or m.get("max_tokens") or 0,
                "max_context": m.get("max_context") or m.get("context_window") or 0,
            })
        return jsonify({
            "success": True,
            "models": safe_models,
            "default_model": default_model,
        })
    except Exception as exc:
        return jsonify({"success": False, "error": str(exc)}), 500


@multi_agent_bp.route("/api/multiagent/active_sub_agents", methods=["GET"])
@api_login_required
def list_active_sub_agents_api():
    """查询当前会话所有子智能体实例（多智能体模式专用）。"""
    username = get_current_username()
    if not username:
        return jsonify({"success": False, "error": "未登录"}), 401
    conversation_id = (request.args.get("conversation_id") or "").strip()
    if not conversation_id:
        return jsonify({"success": False, "error": "缺少 conversation_id 参数"}), 400
    terminal, _ = get_user_resources(username)
    if not terminal:
        return jsonify({"success": False, "error": "工作区未就绪"}), 503
    sub_agent_manager = getattr(terminal, "sub_agent_manager", None)
    if not sub_agent_manager:
        return jsonify({"success": False, "error": "子智能体管理器未就绪"}), 503
    state = sub_agent_manager.get_multi_agent_state(conversation_id)
    if not state:
        return jsonify({"success": True, "agents": []})
    return jsonify({
        "success": True,
        "agents": [a.to_dict() for a in state.list_all()],
    })


__all__ = ["multi_agent_bp"]