"""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
    from butler.skills.log_skill import LogSkill

    tmux = TmuxWrapper(session_prefix=settings.session_prefix)
    log_skill = LogSkill()

    # 检查权限
    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)
        raw_output = tmux.capture_pane(session_name)
        return {
            "reply": "已发送按键到交互程序",
            "mode": "interactive",
            "raw_output_id": None,
        }

    # 自然语言模式：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 "",
        }
        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 {
            "reply": f"⚠️ 该操作需要确认：{reason}。将执行 `{command}`，确认吗？",
            "mode": "pending_approval",
            "command": command,
        }

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

    # 记录到日志（保存原始输出）
    log_skill.log_command(msg.user_id, session_name, command, raw_output[:2000])

    # Claude 总结输出
    if agent.is_available():
        summary = await agent.summarize(original_input, command, raw_output)
    else:
        summary = f"执行了 `{command}`\n{raw_output[-500:]}"

    return {
        "reply": summary,
        "mode": "nl",
        "command": command,
        "raw_output_id": None,  # TODO: 可关联日志 ID
    }


@app.get("/api/raw-output")
async def get_raw_output(user_id: str, limit: int = 5) -> dict[str, Any]:
    """获取命令的原始输出（从日志）。"""
    from butler.skills.log_skill import LogSkill

    log_skill = LogSkill()
    conn = __import__("sqlite3").connect(log_skill.db_path)
    cursor = conn.execute(
        "SELECT command, output, timestamp FROM shell_logs WHERE user_id = ? ORDER BY timestamp DESC LIMIT ?",
        (user_id, limit),
    )
    rows = cursor.fetchall()
    conn.close()

    logs = [
        {"command": row[0], "output": row[1], "timestamp": row[2]}
        for row in rows
    ]
    return {"user_id": user_id, "logs": logs}


@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()
