"""Agent lifecycle and chat routes."""

import asyncio
import json

from fastapi import APIRouter, HTTPException
from fastapi.responses import JSONResponse, StreamingResponse
from pydantic import ValidationError

from AutoGLM_GUI.logger import logger
from AutoGLM_GUI.schemas import (
    AbortRequest,
    ChatRequest,
    ChatResponse,
    ConfigResponse,
    ConfigSaveRequest,
    ResetRequest,
    StatusResponse,
)
from AutoGLM_GUI.version import APP_VERSION

router = APIRouter()


SSEPayload = dict[str, str | int | bool | None | dict]


def _create_sse_event(
    event_type: str, data: SSEPayload, role: str = "assistant"
) -> SSEPayload:
    """Create an SSE event with standardized fields including role."""
    event_data = {"type": event_type, "role": role, **data}
    return event_data


@router.post("/api/chat", response_model=ChatResponse)
async def chat(request: ChatRequest) -> ChatResponse:
    """发送任务给 Agent 并执行（支持 AsyncAgent）。

    Agent 会在首次使用时自动初始化，无需手动预初始化。
    """
    from AutoGLM_GUI.exceptions import AgentInitializationError, DeviceBusyError
    from AutoGLM_GUI.phone_agent_manager import PhoneAgentManager

    device_id = request.device_id
    manager = PhoneAgentManager.get_instance()

    acquired = False
    try:
        acquired = await asyncio.to_thread(
            manager.acquire_device, device_id, timeout=None, auto_initialize=True
        )
        # Use chat context with async agent
        agent = await asyncio.to_thread(
            manager.get_agent_with_context,
            device_id,
            context="chat",
            agent_type="glm-async",
        )

        # AsyncAgent is always used for chat context
        result = await agent.run(request.message)  # type: ignore[misc]

        steps = agent.step_count
        return ChatResponse(result=result, steps=steps, success=True)  # type: ignore[arg-type]

    except AgentInitializationError as e:
        logger.error(f"Failed to initialize agent for {device_id}: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"初始化失败: {str(e)}. 请检查全局配置 (base_url, api_key, model_name)",
        )
    except DeviceBusyError:
        raise HTTPException(
            status_code=409, detail=f"Device {device_id} is busy. Please wait."
        )
    except Exception as e:
        logger.exception(f"Unexpected error in chat for {device_id}")
        return ChatResponse(result=str(e), steps=0, success=False)
    finally:
        if acquired:
            await asyncio.to_thread(manager.release_device, device_id)


@router.post("/api/chat/stream")
async def chat_stream(request: ChatRequest):
    """发送任务给 Agent 并实时推送执行进度（SSE，多设备支持）。

    Agent 会在首次使用时自动初始化，无需手动预初始化。

    Chat API 使用 AsyncAgent 实现原生 async streaming 和立即取消。
    """
    from datetime import datetime

    from AutoGLM_GUI.device_manager import DeviceManager
    from AutoGLM_GUI.exceptions import AgentInitializationError, DeviceBusyError
    from AutoGLM_GUI.history_manager import history_manager
    from AutoGLM_GUI.models.history import ConversationRecord, MessageRecord
    from AutoGLM_GUI.phone_agent_manager import PhoneAgentManager

    device_id = request.device_id
    manager = PhoneAgentManager.get_instance()

    # ===== 在外层获取设备锁 =====
    acquired = False
    try:
        acquired = await asyncio.to_thread(
            manager.acquire_device,
            device_id,
            timeout=0,
            raise_on_timeout=True,
            auto_initialize=True,
        )
    except DeviceBusyError:
        logger.warning(f"Device {device_id} is busy, returning 409")
        return JSONResponse(
            status_code=409,
            content={"detail": f"Device {device_id} is busy. Please wait."},
        )
    except AgentInitializationError as e:
        logger.error(f"Failed to initialize agent for {device_id}: {e}")
        return JSONResponse(
            status_code=500,
            content={
                "detail": f"初始化失败: {str(e)}. 请检查全局配置 (base_url, api_key, model_name)"
            },
        )

    logger.info(f"Device lock acquired for {device_id}")

    async def event_generator():
        start_time = datetime.now()
        final_message = ""
        final_success = False
        final_steps = 0

        # 收集完整对话消息
        messages: list[MessageRecord] = []
        # 添加用户消息
        messages.append(
            MessageRecord(
                role="user",
                content=request.message,
                timestamp=start_time,
            )
        )

        try:
            # 使用 chat context 获取 AsyncAgent
            agent = await asyncio.to_thread(
                manager.get_agent_with_context,
                device_id,
                context="chat",
                agent_type="glm-async",
            )

            logger.info(f"Using AsyncAgent for device {device_id}")

            # 注册异步取消处理器
            async def cancel_handler():
                await agent.cancel()  # type: ignore[union-attr]

            await asyncio.to_thread(
                manager.register_abort_handler, device_id, cancel_handler
            )

            # 直接使用 agent.stream()
            async for event in agent.stream(request.message):  # type: ignore[union-attr]
                event_type = event["type"]
                event_data_dict = event["data"]

                # 收集每个 step 的消息
                if event_type == "step":
                    messages.append(
                        MessageRecord(
                            role="assistant",
                            content="",
                            timestamp=datetime.now(),
                            thinking=event_data_dict.get("thinking"),
                            action=event_data_dict.get("action"),
                            step=event_data_dict.get("step"),
                        )
                    )

                if event_type == "done":
                    final_message = event_data_dict.get("message", "")
                    final_success = event_data_dict.get("success", False)
                    final_steps = event_data_dict.get("steps", 0)

                # 发送 SSE 事件
                sse_event = _create_sse_event(event_type, event_data_dict)
                yield f"event: {event_type}\n"
                yield f"data: {json.dumps(sse_event, ensure_ascii=False)}\n\n"

        except asyncio.CancelledError:
            logger.info(f"AsyncAgent task cancelled for device {device_id}")
            yield "event: cancelled\n"
            yield f"data: {json.dumps({'message': 'Task cancelled by user'})}\n\n"
            # ✅ 不再 raise，让 generator 正常结束

        except AgentInitializationError as e:
            logger.error(f"Failed to initialize agent for {device_id}: {e}")
            error_data = _create_sse_event(
                "error",
                {
                    "message": f"初始化失败: {str(e)}",
                    "hint": "请检查全局配置 (base_url, api_key, model_name)",
                },
            )
            yield "event: error\n"
            yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n"

        except Exception as e:
            logger.exception(f"Error in streaming chat for {device_id}")
            error_data = _create_sse_event("error", {"message": str(e)})
            yield "event: error\n"
            yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n"

        finally:
            # ===== 无论 generator 如何结束都释放锁 =====
            # 覆盖：正常完成、取消、异常、客户端断开(aclose)
            try:
                await asyncio.to_thread(manager.unregister_abort_handler, device_id)
            except Exception:
                pass
            if acquired:
                try:
                    await asyncio.to_thread(manager.release_device, device_id)
                    logger.info(f"Device lock released for {device_id}")
                except Exception as e:
                    logger.error(f"Failed to release device lock for {device_id}: {e}")

        # ===== 保存历史记录 =====
        device_manager = DeviceManager.get_instance()
        serialno = device_manager.get_serial_by_device_id(device_id)
        if serialno and final_message:
            end_time = datetime.now()
            record = ConversationRecord(
                task_text=request.message,
                final_message=final_message,
                success=final_success,
                steps=final_steps,
                start_time=start_time,
                end_time=end_time,
                duration_ms=int((end_time - start_time).total_seconds() * 1000),
                source="chat",
                error_message=None if final_success else final_message,
                messages=messages,
            )
            history_manager.add_record(serialno, record)

    return StreamingResponse(
        event_generator(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "X-Accel-Buffering": "no",
        },
    )


@router.get("/api/status", response_model=StatusResponse)
def get_status(device_id: str | None = None) -> StatusResponse:
    """获取 Agent 状态和版本信息（多设备支持）。"""
    from AutoGLM_GUI.phone_agent_manager import PhoneAgentManager

    manager = PhoneAgentManager.get_instance()

    if device_id is None:
        return StatusResponse(
            version=APP_VERSION,
            initialized=len(manager.list_agents()) > 0,
            step_count=0,
        )

    if not manager.is_initialized(device_id):
        return StatusResponse(
            version=APP_VERSION,
            initialized=False,
            step_count=0,
        )

    agent = manager.get_agent(device_id)
    return StatusResponse(
        version=APP_VERSION,
        initialized=True,
        step_count=agent.step_count,
    )


@router.post("/api/reset")
def reset_agent(request: ResetRequest) -> dict:
    """重置 Agent 状态（多设备支持）。"""
    from AutoGLM_GUI.exceptions import AgentNotInitializedError
    from AutoGLM_GUI.phone_agent_manager import PhoneAgentManager

    device_id = request.device_id
    manager = PhoneAgentManager.get_instance()

    try:
        manager.reset_agent(device_id)
        return {
            "success": True,
            "device_id": device_id,
            "message": f"Agent reset for device {device_id}",
        }
    except AgentNotInitializedError:
        raise HTTPException(status_code=404, detail=f"Device {device_id} not found")


@router.post("/api/chat/abort")
async def abort_chat(request: AbortRequest) -> dict:
    """中断正在进行的对话流 (支持 AsyncAgent)。"""
    from AutoGLM_GUI.phone_agent_manager import PhoneAgentManager

    device_id = request.device_id
    manager = PhoneAgentManager.get_instance()

    # 使用异步方法 (支持 AsyncAgent 和 BaseAgent)
    success = await manager.abort_streaming_chat_async(device_id)

    return {
        "success": success,
        "message": "Abort requested" if success else "No active chat found",
    }


@router.get("/api/config", response_model=ConfigResponse)
def get_config_endpoint() -> ConfigResponse:
    """获取当前有效配置."""
    from AutoGLM_GUI.config_manager import config_manager

    # 热重载：检查文件是否被外部修改
    config_manager.load_file_config()

    # 获取有效配置和来源
    effective_config = config_manager.get_effective_config()
    source = config_manager.get_config_source()

    # 检测冲突
    conflicts = config_manager.detect_conflicts()

    return ConfigResponse(
        base_url=effective_config.base_url,
        model_name=effective_config.model_name,
        api_key=effective_config.api_key if effective_config.api_key != "EMPTY" else "",
        source=source.value,
        agent_type=effective_config.agent_type,
        agent_config_params=effective_config.agent_config_params,
        default_max_steps=effective_config.default_max_steps,
        layered_max_turns=effective_config.layered_max_turns,
        decision_base_url=effective_config.decision_base_url,
        decision_model_name=effective_config.decision_model_name,
        decision_api_key=effective_config.decision_api_key,
        conflicts=[
            {
                "field": c.field,
                "file_value": c.file_value,
                "override_value": c.override_value,
                "override_source": c.override_source.value,
            }
            for c in conflicts
        ]
        if conflicts
        else None,
    )


@router.post("/api/config")
def save_config_endpoint(request: ConfigSaveRequest) -> dict:
    """保存配置到文件.

    配置保存后需重启应用以立即生效。
    """
    from AutoGLM_GUI.config_manager import ConfigModel, config_manager

    try:
        # Validate incoming configuration
        ConfigModel(
            base_url=request.base_url,
            model_name=request.model_name,
            api_key=request.api_key or "EMPTY",
        )

        # 保存配置（合并模式，不丢失字段）
        success = config_manager.save_file_config(
            base_url=request.base_url,
            model_name=request.model_name,
            api_key=request.api_key,
            agent_type=request.agent_type,
            agent_config_params=request.agent_config_params,
            default_max_steps=request.default_max_steps,
            layered_max_turns=request.layered_max_turns,
            decision_base_url=request.decision_base_url,
            decision_model_name=request.decision_model_name,
            decision_api_key=request.decision_api_key,
            merge_mode=True,
        )

        if not success:
            raise HTTPException(status_code=500, detail="Failed to save config")

        # 同步到环境变量
        config_manager.sync_to_env()

        # 检测冲突并返回警告
        conflicts = config_manager.detect_conflicts()

        response_message = (
            f"Configuration saved to {config_manager.get_config_path()}."
            " Restart required to apply new configuration immediately."
        )

        if conflicts:
            warnings = [
                f"{c.field}: file value overridden by {c.override_source.value}"
                for c in conflicts
            ]
            return {
                "success": True,
                "message": response_message,
                "warnings": warnings,
                "restart_required": True,
            }

        return {
            "success": True,
            "message": response_message,
            "restart_required": True,
        }

    except ValidationError as e:
        raise HTTPException(status_code=400, detail=f"Invalid configuration: {e}")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/api/config")
def delete_config_endpoint() -> dict:
    """删除配置文件."""
    from AutoGLM_GUI.config_manager import config_manager

    try:
        success = config_manager.delete_file_config()

        if not success:
            raise HTTPException(status_code=500, detail="Failed to delete config")

        return {"success": True, "message": "Configuration deleted"}

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# ✅ 已删除 /api/agents/reinit-all 端点
# 原因：配置保存时自动销毁所有 Agent（副作用），无需单独的 reinit 端点
# 见 /api/config POST 端点的实现
