"""SSO router: OIDC login and callback (build plan Section 8)."""

from __future__ import annotations

import secrets

from fastapi import APIRouter, Depends, HTTPException, Query, status
from fastapi.responses import RedirectResponse
from sqlalchemy.orm import Session

from legate.config import get_settings
from legate.db.session import get_db
from legate.observability.logging import get_logger
from legate.repositories import users as users_repo
from legate.security.oidc import OIDCError, get_oidc_client
from legate.security.tokens import create_access_token, create_refresh_token

logger = get_logger(__name__)
router = APIRouter(prefix="/auth/oidc", tags=["auth"])


def _require_enabled() -> None:
    if not get_settings().oidc_enabled:
        raise HTTPException(status.HTTP_404_NOT_FOUND, detail="SSO is not enabled")


@router.get("/login")
def oidc_login() -> RedirectResponse:
    _require_enabled()
    state = secrets.token_urlsafe(16)
    url = get_oidc_client().authorization_url(state)
    return RedirectResponse(url, status_code=status.HTTP_307_TEMPORARY_REDIRECT)


@router.get("/callback")
def oidc_callback(
    code: str = Query(...),
    state: str = Query(default=""),
    db: Session = Depends(get_db),
) -> RedirectResponse:
    _require_enabled()
    try:
        identity = get_oidc_client().exchange_code(code)
    except OIDCError as exc:
        raise HTTPException(status.HTTP_401_UNAUTHORIZED, detail=str(exc)) from exc
    if not identity.email:
        raise HTTPException(status.HTTP_400_BAD_REQUEST, detail="IdP returned no email")

    user = users_repo.get_by_email(db, identity.email)
    if user is None:
        user = users_repo.create(
            db, email=identity.email, password_hash=None, name=identity.name, is_active=True
        )
    elif not user.is_active:
        user.is_active = True
    db.commit()
    db.refresh(user)
    access = create_access_token(user.id)
    refresh = create_refresh_token(user.id)

    # Hand the tokens back to the dashboard via the URL fragment.
    web = get_settings().web_base_url.rstrip("/")
    return RedirectResponse(
        f"{web}/login#access_token={access}&refresh_token={refresh}",
        status_code=status.HTTP_302_FOUND,
    )
