import asyncio
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager

from fastapi import APIRouter, FastAPI
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy import select, update

from src.admin.router import router as admin_router
from src.auth.router import router as auth_router
from src.core.config import settings
from src.core.db import SessionLocal, reinit_database
from src.events.router import router as events_router
from src.group_settings.models import GroupConfig  # noqa: F401 — registers model with metadata
from src.group_settings.router import router as settings_router
from src.pages.router import router as pages_router
from src.services.notification_service import check_and_send_notifications
from src.users.models import User
from src.users.router import router as users_router
from fastapi import Request, HTTPException
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from src.users.repo import UserRepo
from src.group_settings.repo import GroupConfigRepo
from src.services.google_groups import is_group_admin
from src.core.deps import get_optional_current_user

templates = Jinja2Templates(directory="src/templates")

API_PREFIX = "/v1"


async def _promote_super_admin() -> None:
    """If SUPER_ADMIN_EMAIL is configured, ensure that user has is_admin=True."""
    if not settings.super_admin_email:
        return
    async with SessionLocal() as session:
        result = await session.execute(
            select(User).where(User.email == settings.super_admin_email)
        )
        user = result.scalar_one_or_none()
        if user and not user.is_admin:
            await session.execute(
                update(User)
                .where(User.email == settings.super_admin_email)
                .values(is_admin=True)
            )
            await session.commit()


@asynccontextmanager  # pragma: no cover
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
    if settings.reset_db_on_startup:
        await reinit_database()
    else:
        # Ensure tables exist even if we aren't resetting
        from src.core.db import init_database
        await init_database()

    await _promote_super_admin()

    # Start the background notification task
    asyncio.create_task(check_and_send_notifications())

    yield


app = FastAPI(lifespan=lifespan)


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

router = APIRouter(prefix=API_PREFIX)
router.include_router(users_router)
router.include_router(auth_router)
router.include_router(events_router)
router.include_router(settings_router)
router.include_router(admin_router)

app.include_router(router)
app.include_router(pages_router)


@app.exception_handler(HTTPException)
async def html_exception_handler(request: Request, exc: HTTPException):
    """Render a pretty HTML page for HTTPExceptions if the request is not an API call."""
    # If it's an API request (starts with /v1), return JSON as usual
    if request.url.path.startswith(API_PREFIX):
        return await _default_http_exception_handler(request, exc)

    # Try to get the current user for the navbar
    user = None
    is_sa = False
    is_ga = False
    try:
        async with SessionLocal() as session:
            user_repo = UserRepo(session)
            group_repo = GroupConfigRepo(session)
            user = await get_optional_current_user(request, user_repo)
            if user:
                is_sa = user.is_admin
                # Try to find if they are an admin of any group for the navbar logic
                all_configs = await group_repo.get_all()
                for config in all_configs:
                    if is_group_admin(user.email, config):
                        is_ga = True
                        break
    except Exception:
        pass

    import http
    reason = http.HTTPStatus(exc.status_code).phrase

    return templates.TemplateResponse(
        request=request,
        name="error.html",
        status_code=exc.status_code,
        context={
            "request": request,
            "status_code": exc.status_code,
            "reason": reason,
            "detail": exc.detail,
            "user": user,
            "is_super_admin": is_sa,
            "is_group_admin": is_ga,
        },
    )


async def _default_http_exception_handler(request, exc):
    from fastapi.exception_handlers import http_exception_handler
    return await http_exception_handler(request, exc)
