from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from starlette.middleware.sessions import SessionMiddleware

from app.core.settings import get_settings
from app.core.middleware.context import ContextResolveMiddleware
from app.core.middleware.domain_resolver import DomainResolverMiddleware
from app.core.middleware.security_headers import SecurityHeadersMiddleware
from app.core.middleware.csrf_guard import CsrfPostGuardMiddleware
from app.core.startup import on_startup
from app.core.api import api_router
from app.core.http_responses import auth_required_response, forbidden_response, not_found_response, wants_json
from app.ui.app import mount_ui


def _register_error_handlers(app: FastAPI) -> None:
    @app.exception_handler(PermissionError)
    async def permission_error_handler(request: Request, exc: PermissionError):
        message = str(exc) or "Access denied"
        if "csrf" in message.lower():
            return JSONResponse({"detail": "CSRF validation failed"}, status_code=403) if wants_json(request) else forbidden_response(request, "CSRF validation failed")
        if "not authenticated" in message.lower():
            return auth_required_response(request)
        return forbidden_response(request, message)

    @app.exception_handler(HTTPException)
    async def http_exception_handler(request: Request, exc: HTTPException):
        detail = exc.detail if isinstance(exc.detail, str) else "Error"
        if request.url.path.startswith("/api"):
            return JSONResponse({"detail": exc.detail}, status_code=exc.status_code, headers=exc.headers)
        if exc.status_code == 401:
            return auth_required_response(request)
        if exc.status_code == 403:
            return forbidden_response(request, detail or "Access denied")
        if exc.status_code == 404:
            return not_found_response(request, detail or "Not found")
        return JSONResponse({"detail": exc.detail}, status_code=exc.status_code, headers=exc.headers)


def create_app() -> FastAPI:
    s = get_settings()
    app = FastAPI(title=s.APP_NAME, debug=s.DEBUG)

    app.add_middleware(SecurityHeadersMiddleware)
    app.add_middleware(ContextResolveMiddleware)
    # Phase 7T.2: added after context so it resolves the request host before
    # context-aware middleware/routes need tenant/branch/domain state.
    app.add_middleware(DomainResolverMiddleware)
    # Runs after SessionMiddleware has populated request.session and before routes.
    # It only guards selected UI unsafe POST endpoints and does not change valid forms.
    app.add_middleware(CsrfPostGuardMiddleware)
    # SessionMiddleware is added last so it is available to downstream
    # middleware/routes in Starlette's middleware execution order.
    app.add_middleware(
        SessionMiddleware,
        secret_key=s.SECRET_KEY,
        session_cookie=s.COOKIE_SESSION_NAME,
        same_site=s.COOKIE_SAMESITE,
        https_only=s.COOKIE_SECURE,
    )

    app.add_event_handler("startup", lambda: on_startup(app))
    _register_error_handlers(app)

    app.include_router(api_router, prefix="/api")
    mount_ui(app)

    return app


app = create_app()
