"""project_auth domain — HTTP routes.

All routes live under /api/projects/{project_id}/auth/...
Access requires the caller to be an authenticated workspace member with billing active.
"""
from __future__ import annotations

from uuid import UUID

from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession

from src.core.database import get_db
from src.core.dependencies import require_active_billing_for_project_id
from src.domain.auth.models import User
from src.domain.auth.router import get_current_user
from src.domain.project_auth.repository import (
    ProjectAuthConfigRepository,
    ProjectAuthKeyRepository,
    ProjectAuthRoleRepository,
)
from src.domain.project_auth.schemas import (
    AuthConfigResponse,
    AuthKeyResponse,
    AuthRoleResponse,
    CreateAuthRoleRequest,
    RotateKeyResponse,
    RevokeAppUserRequest,
    UpdateAuthRoleRequest,
    UpsertAuthConfigRequest,
)
from src.domain.project_auth.service import ProjectAuthService
from src.integrations.cloud_control_client import CloudControlClient

router = APIRouter(prefix="/api/projects/{project_id}/auth", tags=["project-auth"])


def _get_service(db: AsyncSession = Depends(get_db)) -> ProjectAuthService:
    return ProjectAuthService(
        config_repo=ProjectAuthConfigRepository(db),
        key_repo=ProjectAuthKeyRepository(db),
        role_repo=ProjectAuthRoleRepository(db),
        cloud_client=CloudControlClient(),
    )


# ---------------------------------------------------------------------------
# Auth Config
# ---------------------------------------------------------------------------


@router.put("/config", response_model=AuthConfigResponse)
async def upsert_auth_config(
    body: UpsertAuthConfigRequest,
    project_id: UUID = Depends(require_active_billing_for_project_id),
    _: User = Depends(get_current_user),
    svc: ProjectAuthService = Depends(_get_service),
) -> AuthConfigResponse:
    """Create or update auth configuration for a project.

    Immediately syncs the new config to Cloud via the control plane.
    """
    return await svc.upsert_config(project_id, body)


@router.get("/config", response_model=AuthConfigResponse)
async def get_auth_config(
    project_id: UUID = Depends(require_active_billing_for_project_id),
    _: User = Depends(get_current_user),
    svc: ProjectAuthService = Depends(_get_service),
) -> AuthConfigResponse:
    return await svc.get_config(project_id)


# ---------------------------------------------------------------------------
# RS256 Keys
# ---------------------------------------------------------------------------


@router.post("/keys/rotate", response_model=RotateKeyResponse)
async def rotate_auth_key(
    project_id: UUID = Depends(require_active_billing_for_project_id),
    _: User = Depends(get_current_user),
    svc: ProjectAuthService = Depends(_get_service),
) -> RotateKeyResponse:
    """Generate a new RS256 key pair.

    The previous active key is marked 'rotated'. Existing app tokens referencing
    the old key will continue to work until they expire naturally. Cloud receives
    the new public key immediately via the control plane.
    """
    return await svc.rotate_key(project_id)


@router.get("/keys", response_model=list[AuthKeyResponse])
async def list_auth_keys(
    project_id: UUID = Depends(require_active_billing_for_project_id),
    _: User = Depends(get_current_user),
    svc: ProjectAuthService = Depends(_get_service),
) -> list[AuthKeyResponse]:
    """List all key pairs for this project (private key is never returned)."""
    return await svc.list_keys(project_id)


# ---------------------------------------------------------------------------
# Custom Roles
# ---------------------------------------------------------------------------


@router.get("/roles", response_model=list[AuthRoleResponse])
async def list_roles(
    project_id: UUID = Depends(require_active_billing_for_project_id),
    _: User = Depends(get_current_user),
    svc: ProjectAuthService = Depends(_get_service),
) -> list[AuthRoleResponse]:
    return await svc.list_roles(project_id)


@router.post("/roles", response_model=AuthRoleResponse, status_code=201)
async def create_role(
    body: CreateAuthRoleRequest,
    project_id: UUID = Depends(require_active_billing_for_project_id),
    _: User = Depends(get_current_user),
    svc: ProjectAuthService = Depends(_get_service),
) -> AuthRoleResponse:
    """Create a custom role. Syncs updated roles to Cloud immediately."""
    return await svc.create_role(project_id, body)


@router.patch("/roles/{role_name}", response_model=AuthRoleResponse)
async def update_role(
    role_name: str,
    body: UpdateAuthRoleRequest,
    project_id: UUID = Depends(require_active_billing_for_project_id),
    _: User = Depends(get_current_user),
    svc: ProjectAuthService = Depends(_get_service),
) -> AuthRoleResponse:
    return await svc.update_role(project_id, role_name, body)


@router.delete("/roles/{role_name}", status_code=204, response_model=None)
async def delete_role(
    role_name: str,
    project_id: UUID = Depends(require_active_billing_for_project_id),
    _: User = Depends(get_current_user),
    svc: ProjectAuthService = Depends(_get_service),
) -> None:
    await svc.delete_role(project_id, role_name)


# ---------------------------------------------------------------------------
# Revocation
# ---------------------------------------------------------------------------


@router.post("/users/{user_id}/revoke", status_code=204, response_model=None)
async def revoke_app_user(
    user_id: str,
    body: RevokeAppUserRequest,
    project_id: UUID = Depends(require_active_billing_for_project_id),
    _: User = Depends(get_current_user),
    svc: ProjectAuthService = Depends(_get_service),
) -> None:
    """Revoke an app user's access immediately.

    Pushes a revocation entry to Cloud KV. Any app JWT for this user will be
    rejected on the next request regardless of expiry.
    """
    body.user_id = user_id
    await svc.revoke_app_user(project_id, body)
