import asyncio
import json
import logging
from contextlib import asynccontextmanager
from pathlib import Path
from typing import Any, AsyncGenerator

from dotenv import load_dotenv
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles

from nyahome.config import config_manager
from nyahome.core.otp_store import email_otp_memory_store
from nyahome.core.send_email import email_sender_queue
from nyahome.core.task import init_admin_user
from nyahome.database import create_db
from nyahome.router import admin_router, aii_router, chatroom_router, file_router, webui_router

logger = logging.getLogger(__name__)


@asynccontextmanager
async def lifespan(app_: FastAPI) -> AsyncGenerator[None, Any]:
    load_dotenv(Path.cwd() / ".nyahome" / ".env")
    logger.info("🚀 服务启动中...")
    create_db()
    await asyncio.gather(init_admin_user(), config_manager.async_load_config())
    email_sender_queue.start()
    email_otp_memory_store.start()
    logger.info("🌸 server 启动完成。")

    try:
        yield
    except Exception as e:
        logger.error(f"捕获到无法处理的异常，NyaHome 即将结束 - {e}")
    finally:
        logger.info("🌕 服务关闭中...")


app = FastAPI(title="🌸 NyaHome ~", lifespan=lifespan)

app.include_router(webui_router)
app.include_router(chatroom_router, prefix="/api")
app.include_router(admin_router, prefix="/api")
app.include_router(file_router, prefix="/api")
app.include_router(aii_router, prefix="/api")

app.mount("/nyahome", StaticFiles(directory=Path.cwd() / "public"), name="public")
app.mount("/download", StaticFiles(directory=Path.cwd() / ".nyahome/contents"), name="upload")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


def save_openapi_json(save_path: str | Path) -> None:
    from docstring_parser import DocstringStyle

    from nyahome.cli.openapi_docstring import enrich_openapi_from_docstrings

    # 增强 openapi docstring 参数文档提取
    enrich_openapi_from_docstrings(app, docstring_style=DocstringStyle.GOOGLE)

    with open(save_path, "w") as f:
        json.dump(app.openapi(), f, indent=2)
