from pathlib import Path

from fastapi import APIRouter, Depends, FastAPI
from fastapi.staticfiles import StaticFiles
from starlette.exceptions import HTTPException

from flyway.api import (
    errors, routes_account, routes_auth, routes_clients_extra, routes_dashboard, routes_load_ins, routes_load_outs,
    routes_lookup, routes_master, routes_packing, routes_parcels, routes_print, routes_reports, routes_transfers,
    routes_users, routes_backups,
)
from flyway.api.deps import current_actor, set_session_cookie
from flyway.config import settings

PUBLIC_PATHS = {"/api/health", "/api/auth/login"}


class SpaFiles(StaticFiles):
    """生产环境由后端同源提供前端构建产物；前端路由（如 /load-ins/xxx）回退到 index.html，/api 下的未知路径仍是 404。"""

    async def get_response(self, path, scope):
        try:
            return await super().get_response(path, scope)
        except HTTPException as e:
            if e.status_code != 404 or path.startswith("api"):
                raise
            return await super().get_response("index.html", scope)


def create_app() -> FastAPI:
    # 接口文档默认关闭（文档第 3 节：只有登录接口公开）；本机开发可设 FLYWAY_API_DOCS=true
    docs = settings.api_docs
    app = FastAPI(title="Flyway", docs_url="/docs" if docs else None, redoc_url="/redoc" if docs else None,
                  openapi_url="/openapi.json" if docs else None)
    errors.install(app)

    @app.middleware("http")
    async def renew_session_cookie(request, call_next):
        """current_actor 续期了会话时，在响应上重发 Cookie（对直接返回 PDF / Excel 的接口同样有效）。"""
        response = await call_next(request)
        renew = getattr(request.state, "renew_cookie", None)
        if renew:
            set_session_cookie(response, *renew)
        return response

    @app.get("/api/health")
    def health():
        return {"status": "ok"}

    app.include_router(routes_auth.public)
    # 全局默认需要登录：业务路由一律挂在 protected 下（文档 3“新系统权限要求”第 1 条）
    protected = APIRouter(dependencies=[Depends(current_actor)])
    protected.include_router(routes_auth.protected)
    protected.include_router(routes_users.router)
    protected.include_router(routes_backups.router)
    protected.include_router(routes_account.router)
    protected.include_router(routes_master.router)
    protected.include_router(routes_load_ins.router)
    protected.include_router(routes_load_outs.router)
    protected.include_router(routes_transfers.router)
    protected.include_router(routes_packing.router)
    protected.include_router(routes_lookup.router)
    protected.include_router(routes_dashboard.router)
    protected.include_router(routes_master.admin_router)
    protected.include_router(routes_print.router)
    protected.include_router(routes_reports.router)
    protected.include_router(routes_parcels.router)
    protected.include_router(routes_clients_extra.router)
    protected.include_router(routes_print.admin_router)
    app.include_router(protected)
    if settings.frontend_dist and Path(settings.frontend_dist).is_dir():
        app.mount("/", SpaFiles(directory=settings.frontend_dist, html=True), name="frontend")
    return app


app = create_app()
