from __future__ import annotations

from contextlib import asynccontextmanager

from fastapi import FastAPI, Request
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles

from ..core.logger import AppLogger
from ..core.settings import PROJECT_ROOT, get_settings
from ..database import SessionLocal, init_database
from ..repositories import OrganizationRepository, SalaryConfigRepository, UserRepository
from ..services import AuthService, OrganizationService, SalaryConfigService
from .routers import (
    auth,
    commissions,
    configs,
    employees,
    health,
    monthly_payroll,
    operation_logs,
    organization,
    payroll,
    realtime_attendance,
    reports,
    salary_profiles,
)

logger = AppLogger.get_logger(__name__)


@asynccontextmanager
async def lifespan(_: FastAPI):
    """应用启动时建表并保证至少有一个超级用户。"""
    logger.info("应用启动初始化开始")
    try:
        init_database()
        _bootstrap_superuser()
        _bootstrap_salary_configs()
        _bootstrap_departments()
    except Exception:
        logger.exception("应用启动初始化失败")
        raise
    logger.info("应用启动初始化完成")
    yield
    logger.info("应用关闭")


def create_app() -> FastAPI:
    """集中创建 FastAPI 应用，路由注册和启动生命周期都在这里完成。"""
    settings = get_settings()
    AppLogger.configure(settings)
    logger.info("创建 FastAPI 应用 config_path=%s", settings.config_path)
    app = FastAPI(
        title="Financial System Payroll API",
        description="支持导入月度汇总 Excel，也支持对接钉钉实时打卡记录进行工资计算。",
        version="0.1.0",
        docs_url=None,
        lifespan=lifespan,
    )
    _register_cors(app, settings.cors_allowed_origins)
    _mount_local_swagger_assets(app)
    _register_docs_route(app)
    _register_exception_handlers(app)
    app.include_router(auth.router)
    app.include_router(commissions.router)
    app.include_router(configs.router)
    app.include_router(employees.router)
    app.include_router(health.router)
    app.include_router(monthly_payroll.router)
    app.include_router(operation_logs.router)
    app.include_router(organization.router)
    app.include_router(payroll.router)
    app.include_router(realtime_attendance.router)
    app.include_router(reports.router)
    app.include_router(salary_profiles.router)
    return app


def _register_cors(app: FastAPI, allowed_origins: tuple[str, ...]) -> None:
    """允许前端独立端口访问 API，生产环境可通过环境变量收窄来源。"""
    app.add_middleware(
        CORSMiddleware,
        allow_origins=list(allowed_origins),
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )


def _register_exception_handlers(app: FastAPI) -> None:
    @app.exception_handler(Exception)
    async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse:
        logger.exception("未处理异常 method=%s path=%s", request.method, request.url.path)
        return JSONResponse(status_code=500, content={"detail": "服务器内部错误，请查看错误日志"})


def _mount_local_swagger_assets(app: FastAPI) -> None:
    """挂载本地 Swagger 静态文件，避免依赖外部 CDN。"""
    static_dir = PROJECT_ROOT / "static"
    if static_dir.exists():
        app.mount("/static", StaticFiles(directory=static_dir), name="static")
        logger.info("已挂载本地 Swagger 静态资源 static_dir=%s", static_dir)


def _register_docs_route(app: FastAPI) -> None:
    @app.get("/docs", include_in_schema=False)
    def custom_swagger_ui_html():
        return get_swagger_ui_html(
            openapi_url=app.openapi_url,
            title=f"{app.title} - Swagger UI",
            swagger_js_url="/static/swagger-ui/swagger-ui-bundle.js",
            swagger_css_url="/static/swagger-ui/swagger-ui.css",
            swagger_favicon_url="/static/swagger-ui/favicon.png",
        )


def _bootstrap_superuser() -> None:
    """首次运行时初始化超级用户；已有用户时不覆盖数据库。"""
    session = SessionLocal()
    try:
        service = AuthService(UserRepository(session), get_settings())
        service.ensure_bootstrap_superuser()
        logger.info("超级管理员初始化检查完成")
    finally:
        session.close()


def _bootstrap_salary_configs() -> None:
    """首次运行时补齐规则配置中心默认项。"""
    session = SessionLocal()
    try:
        service = SalaryConfigService(SalaryConfigRepository(session))
        service.ensure_defaults()
        logger.info("系统规则配置初始化检查完成")
    finally:
        session.close()


def _bootstrap_departments() -> None:
    """首次运行时补齐组织架构默认部门和岗位。"""
    session = SessionLocal()
    try:
        service = OrganizationService(OrganizationRepository(session))
        service.ensure_default_departments()
        logger.info("组织架构默认部门和岗位初始化检查完成")
    finally:
        session.close()


app = create_app()
