"""FastAPI 主入口。"""

import asyncio
import logging
import os
import uuid
from contextlib import asynccontextmanager
from typing import Any

import inngest
import inngest.fast_api
import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel

from butler.config import settings
from butler.gateway.napcat import NapCatGateway
from butler.workflows import inngest_client
from butler.workflows.handle_message import handle_im_message
from butler.workflows.guardrail import command_guardrail

logging.basicConfig(
    level=getattr(logging, settings.log_level),
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)

gateway = NapCatGateway(
    ws_url=settings.napcat_ws_url,
    access_token=settings.napcat_token,
)


async def run_gateway() -> None:
    """后台运行 Gateway。"""
    def handle_message(event: Any) -> None:
        """同步消息处理函数。"""
        logger.info(f"Received message from {event.user_id}: {event.message[:50]}...")
        # 在后台任务中发送事件
        asyncio.create_task(inngest_client.send(
            inngest.Event(
                name="im/message",
                data={
                    "user_id": str(event.user_id),
                    "content": event.message,
                },
            )
        ))

    gateway.on_message(handle_message)
    await gateway.connect()


@asynccontextmanager
async def lifespan(app: FastAPI):
    """应用生命周期管理。"""
    logger.info("Starting Butler-Shell...")

    gateway_task = asyncio.create_task(run_gateway())

    yield

    logger.info("Shutting down Butler-Shell...")
    await gateway.stop()
    gateway_task.cancel()


app = FastAPI(
    title="Butler-Shell",
    description="Persistent Shell Assistant with QQ Bridge",
    version="0.1.0",
    lifespan=lifespan,
)

# 注册 Inngest 函数
# 开发模式下使用占位签名密钥
_signing_key = settings.inngest_signing_key or os.environ.get(
    "INNGEST_SIGNING_KEY",
    "signkey-dev-placeholder-1234567890123456789012345678901234567890"
)
_dev_client = inngest.Inngest(
    app_id="butler-shell",
    event_key=settings.inngest_event_key or "dev_key",
    signing_key=_signing_key,
    is_production=bool(settings.inngest_signing_key),
)

inngest.fast_api.serve(
    app,
    _dev_client,
    [handle_im_message, command_guardrail],
    serve_path="/api/inngest",
)


@app.get("/health")
async def health() -> dict[str, str]:
    """服务存活检查。"""
    return {"status": "ok"}


@app.get("/ready")
async def ready() -> dict[str, Any]:
    """服务就绪检查。"""
    import subprocess
    try:
        subprocess.run(["tmux", "-V"], capture_output=True, check=True)
        tmux_ok = True
    except Exception:
        tmux_ok = False

    return {
        "status": "ready" if tmux_ok else "degraded",
        "tmux": tmux_ok,
        "gateway": gateway._ws is not None,
    }


class MockMessage(BaseModel):
    """Mock 消息请求。"""
    user_id: str = "test_user_001"
    content: str


@app.post("/api/mock/message")
async def mock_message(msg: MockMessage) -> dict[str, Any]:
    """开发测试端点：处理自然语言消息。"""
    from butler.session.wrapper import TmuxWrapper
    from butler.session import SessionMode
    from butler.security.guardrail import is_dangerous_command, get_danger_reason
    from butler.agent import agent

    tmux = TmuxWrapper(session_prefix=settings.session_prefix)

    # 检查权限
    if not settings.is_user_allowed(msg.user_id):
        return {"status": "unauthorized", "message": f"用户 {msg.user_id} 无权限"}

    # 获取或创建会话
    session_name = tmux.get_or_create_session(msg.user_id)

    # 检测模式
    current_mode = tmux.detect_mode(session_name)

    # 交互模式直接透传
    if current_mode == SessionMode.INTERACTIVE:
        tmux.send_keys(session_name, msg.content, enter=False)
        output = tmux.capture_pane(session_name)
        return {"status": "success", "mode": "interactive", "output": output[-2000:]}

    # 自然语言模式：使用 Claude 理解意图
    original_input = msg.content
    command = msg.content

    if agent.is_available():
        # 获取上下文
        context = {
            "pwd": tmux.capture_pane(session_name)[-500:] if tmux.session_exists(session_name) else "",
        }

        # 让 Claude 理解用户意图并生成命令
        command = await agent.understand(msg.content, context)

        logger.info(f"Agent: '{original_input}' -> '{command}'")

    # 危险命令检查
    if settings.guardrail_enabled and is_dangerous_command(command):
        reason = get_danger_reason(command) or "潜在危险命令"
        return {
            "status": "pending_approval",
            "mode": "nl",
            "original": original_input,
            "command": command,
            "reason": reason
        }

    # 执行命令
    tmux.send_keys(session_name, command, enter=True)
    await asyncio.sleep(0.5)  # 等待命令执行
    output = tmux.capture_pane(session_name)

    # 可选：让 Claude 解释输出
    explanation = None
    if agent.is_available() and len(output) > 100:
        explanation = await agent.explain_output(output, command)

    return {
        "status": "success",
        "mode": "nl",
        "original": original_input,
        "command": command,
        "output": output[-2000:],
        "explanation": explanation
    }


@app.post("/api/approval")
async def handle_approval(user_id: str, approved: bool) -> dict[str, str]:
    """处理用户审批响应。"""
    await inngest_client.send(
        inngest.Event(
            name="im/approval-response",
            data={"user_id": user_id, "approved": approved},
        )
    )
    return {"status": "sent"}


def main() -> None:
    """启动服务。"""
    uvicorn.run("butler.main:app", host="0.0.0.0", port=8000, reload=False)


if __name__ == "__main__":
    main()
