"""SSO 单点登录路由（Redis 存储 state）"""

import time

from fastapi import APIRouter, Depends, HTTPException, Query, Response
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.cache import cache
from app.config import settings
from app.core.security import create_access_token, create_refresh_token
from app.core.sso import discover_oidc, generate_state, sso_callback_oidc
from app.db import get_db

router = APIRouter()

SSO_STATE_PREFIX = "sso_state:"


@router.get("/{tenant_slug}/initiate", summary="发起SSO")
async def sso_initiate(
    tenant_slug: str,
    provider: str = Query("oidc"),
    redirect_uri: str = Query("/app/feed"),
):
    """发起 SSO 登录 → 重定向到 IdP"""
    if provider != "oidc":
        raise HTTPException(status_code=400, detail="Only OIDC supported currently")

    config = await discover_oidc(tenant_slug)
    if not config:
        raise HTTPException(status_code=400, detail=f"SSO not configured for tenant: {tenant_slug}")

    state = generate_state()
    # Redis 自动过期，10分钟
    await cache.set(SSO_STATE_PREFIX + state, {"expires": time.time() + 600}, ttl=600)
    import secrets
    nonce_val = secrets.token_urlsafe(32)

    # 构建 OIDC Authorization URL
    params = {
        "response_type": "code",
        "client_id": config.client_id,
        "redirect_uri": f"{settings.PUBLIC_BASE_URL}/api/v1/auth/sso/{tenant_slug}/callback",
        "scope": config.scopes,
        "state": state,
        "nonce": nonce_val,
    }
    param_str = "&".join(f"{k}={v}" for k, v in params.items())
    auth_url = f"{config.authorization_endpoint}?{param_str}"

    return {"authorization_url": auth_url, "state": state}


@router.get("/{tenant_slug}/callback", summary="SSO回调")
async def sso_callback(
    tenant_slug: str,
    code: str = Query(...),
    state: str = Query(...),
    response: Response = None,
    db: AsyncSession = Depends(get_db),
):
    """OIDC 回调：验证 → 创建/绑定用户 → 返回 JWT"""
    now = time.time()

    # 验证 state 是否由我们发起（原子 pop）
    stored = await cache.pop(SSO_STATE_PREFIX + state)
    if not stored:
        raise HTTPException(status_code=400, detail="Invalid or expired state parameter")
    if stored.get("expires", 0) < now:
        raise HTTPException(status_code=400, detail="State parameter has expired")

    user_data = await sso_callback_oidc(db, tenant_slug, code, state)

    access_token = create_access_token(
        user_data["user_id"], user_data["tenant_id"], "viewer"
    )
    refresh_token, _ = create_refresh_token(user_data["user_id"], user_data["tenant_id"])

    response.set_cookie(
        key="refresh_token",
        value=refresh_token,
        httponly=True,
        samesite="lax",
        secure=not settings.DEBUG,
        path="/api/v1/auth",
        max_age=settings.REFRESH_TOKEN_EXPIRE_DAYS * 86400,
    )

    return {
        "status": "ok",
        "user": {"email": user_data["email"], "display_name": user_data["display_name"]},
        "tenant": {"name": user_data["tenant_name"]},
        "access_token": access_token,
        "refresh_token": refresh_token,
        "token_type": "bearer",
    }
