"""Admin API endpoints for tenant management.

These endpoints require admin authentication and are used for:
- Creating and managing tenants
- Managing agent access
- Viewing platform-wide statistics
"""

from typing import Annotated, Any

from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel, Field

from pydanticai_multiagent.services import AgentRegistry, TenantService

router = APIRouter(prefix="/admin")


# Request/Response models
class CreateTenantRequest(BaseModel):
    """Request to create a new tenant."""

    name: str = Field(..., description="Tenant name")
    default_model: str = Field(default="openai:gpt-4o", description="Default model for this tenant")
    rate_limit_per_minute: int = Field(default=60, description="Rate limit per minute")
    monthly_token_limit: int | None = Field(default=None, description="Monthly token limit")
    metadata: dict[str, Any] | None = Field(default=None, description="Additional metadata")


class TenantResponse(BaseModel):
    """Response with tenant information."""

    id: str
    name: str
    api_key: str | None = None  # Only included on creation
    default_model: str
    rate_limit_per_minute: int
    monthly_token_limit: int | None
    is_active: bool


class GrantAgentAccessRequest(BaseModel):
    """Request to grant agent access to a tenant."""

    agent_name: str = Field(..., description="Name of the agent")
    model_override: str | None = Field(default=None, description="Model override for this tenant")
    is_default: bool = Field(default=False, description="Set as default agent")


# Dependencies
def get_admin_key(request: Request) -> str:
    """Validate admin API key.

    For production, implement proper admin authentication.
    """
    from pydanticai_multiagent.config import settings

    auth_header = request.headers.get("Authorization")
    if not auth_header:
        raise HTTPException(status_code=401, detail="Authorization required")

    try:
        scheme, token = auth_header.split()
        if scheme.lower() != "bearer":
            raise HTTPException(status_code=401, detail="Invalid auth scheme")
    except ValueError:
        raise HTTPException(status_code=401, detail="Invalid authorization header") from None

    # Simple admin key check - in production use proper admin auth
    admin_key = getattr(settings, "admin_api_key", None) or settings.secret_key
    if token != admin_key:
        raise HTTPException(status_code=403, detail="Invalid admin credentials")

    return token


def get_tenant_service(request: Request) -> TenantService:
    """Get tenant service from app state."""
    db = getattr(request.app.state, "db", None)
    if not db:
        raise HTTPException(status_code=503, detail="Database not available")
    return TenantService(db)


def get_agent_registry(request: Request) -> AgentRegistry:
    """Get agent registry from app state."""
    return request.app.state.agent_registry


# Endpoints
@router.post("/tenants", response_model=TenantResponse)
async def create_tenant(
    body: CreateTenantRequest,
    _admin: Annotated[str, Depends(get_admin_key)],
    service: Annotated[TenantService, Depends(get_tenant_service)],
) -> TenantResponse:
    """Create a new tenant.

    Returns the tenant with the API key (only shown once).
    """
    tenant = await service.create_tenant(
        name=body.name,
        default_model=body.default_model,
        rate_limit_per_minute=body.rate_limit_per_minute,
        monthly_token_limit=body.monthly_token_limit,
        metadata=body.metadata,
    )

    return TenantResponse(
        id=tenant.id,
        name=tenant.name,
        api_key=tenant.api_key,  # Only returned on creation
        default_model=tenant.default_model,
        rate_limit_per_minute=tenant.rate_limit_per_minute,
        monthly_token_limit=tenant.monthly_token_limit,
        is_active=tenant.is_active,
    )


@router.get("/tenants", response_model=list[TenantResponse])
async def list_tenants(
    _admin: Annotated[str, Depends(get_admin_key)],
    service: Annotated[TenantService, Depends(get_tenant_service)],
    include_inactive: bool = False,
) -> list[TenantResponse]:
    """List all tenants."""
    tenants = await service.list_tenants(include_inactive=include_inactive)

    return [
        TenantResponse(
            id=t.id,
            name=t.name,
            default_model=t.default_model,
            rate_limit_per_minute=t.rate_limit_per_minute,
            monthly_token_limit=t.monthly_token_limit,
            is_active=t.is_active,
        )
        for t in tenants
    ]


@router.get("/tenants/{tenant_id}", response_model=TenantResponse)
async def get_tenant(
    tenant_id: str,
    _admin: Annotated[str, Depends(get_admin_key)],
    service: Annotated[TenantService, Depends(get_tenant_service)],
) -> TenantResponse:
    """Get a specific tenant."""
    tenant = await service.get_tenant(tenant_id)
    if not tenant:
        raise HTTPException(status_code=404, detail="Tenant not found")

    return TenantResponse(
        id=tenant.id,
        name=tenant.name,
        default_model=tenant.default_model,
        rate_limit_per_minute=tenant.rate_limit_per_minute,
        monthly_token_limit=tenant.monthly_token_limit,
        is_active=tenant.is_active,
    )


@router.patch("/tenants/{tenant_id}")
async def update_tenant(
    tenant_id: str,
    _admin: Annotated[str, Depends(get_admin_key)],
    service: Annotated[TenantService, Depends(get_tenant_service)],
    name: str | None = None,
    default_model: str | None = None,
    rate_limit_per_minute: int | None = None,
    is_active: bool | None = None,
) -> dict[str, str]:
    """Update a tenant's settings."""
    updated = await service.update_tenant(
        tenant_id=tenant_id,
        name=name,
        default_model=default_model,
        rate_limit_per_minute=rate_limit_per_minute,
        is_active=is_active,
    )

    if not updated:
        raise HTTPException(status_code=400, detail="No updates provided")

    return {"status": "updated", "tenant_id": tenant_id}


@router.post("/tenants/{tenant_id}/agents")
async def grant_agent_access(
    tenant_id: str,
    body: GrantAgentAccessRequest,
    _admin: Annotated[str, Depends(get_admin_key)],
    service: Annotated[TenantService, Depends(get_tenant_service)],
    registry: Annotated[AgentRegistry, Depends(get_agent_registry)],
) -> dict[str, str]:
    """Grant a tenant access to an agent."""
    # Verify tenant exists
    tenant = await service.get_tenant(tenant_id)
    if not tenant:
        raise HTTPException(status_code=404, detail="Tenant not found")

    # Get agent metadata to find the agent_id
    agents = await registry.list_agents()
    agent_match = next((a for a in agents if a.name == body.agent_name), None)

    if not agent_match:
        raise HTTPException(status_code=404, detail=f"Agent '{body.agent_name}' not found")

    await service.grant_agent_access(
        tenant_id=tenant_id,
        agent_id=agent_match.id,
        model_override=body.model_override,
        is_default=body.is_default,
    )

    return {"status": "granted", "tenant_id": tenant_id, "agent": body.agent_name}


@router.delete("/tenants/{tenant_id}/agents/{agent_name}")
async def revoke_agent_access(
    tenant_id: str,
    agent_name: str,
    _admin: Annotated[str, Depends(get_admin_key)],
    service: Annotated[TenantService, Depends(get_tenant_service)],
    registry: Annotated[AgentRegistry, Depends(get_agent_registry)],
) -> dict[str, str]:
    """Revoke a tenant's access to an agent."""
    # Get agent metadata to find the agent_id
    agents = await registry.list_agents()
    agent_match = next((a for a in agents if a.name == agent_name), None)

    if not agent_match:
        raise HTTPException(status_code=404, detail=f"Agent '{agent_name}' not found")

    await service.revoke_agent_access(tenant_id, agent_match.id)

    return {"status": "revoked", "tenant_id": tenant_id, "agent": agent_name}


@router.get("/tenants/{tenant_id}/agents")
async def list_tenant_agents(
    tenant_id: str,
    _admin: Annotated[str, Depends(get_admin_key)],
    service: Annotated[TenantService, Depends(get_tenant_service)],
) -> list[dict[str, Any]]:
    """List agents a tenant has access to."""
    return await service.get_tenant_agents(tenant_id)


@router.get("/agents")
async def list_all_agents(
    _admin: Annotated[str, Depends(get_admin_key)],
    registry: Annotated[AgentRegistry, Depends(get_agent_registry)],
) -> list[dict[str, Any]]:
    """List all registered agents in the platform."""
    agents = await registry.list_agents()
    return [
        {
            "id": a.id,
            "name": a.name,
            "description": a.description,
            "default_model": a.default_model,
            "is_active": a.is_active,
        }
        for a in agents
    ]


class RotateKeyResponse(BaseModel):
    """Response from API key rotation."""

    tenant_id: str
    api_key: str  # New key - only shown once


@router.post("/tenants/{tenant_id}/rotate-key", response_model=RotateKeyResponse)
async def rotate_tenant_key(
    tenant_id: str,
    _admin: Annotated[str, Depends(get_admin_key)],
    service: Annotated[TenantService, Depends(get_tenant_service)],
) -> RotateKeyResponse:
    """Generate a new API key for a tenant.

    The old key is immediately invalidated. Save the new key - it's only shown once.
    """
    new_key = await service.rotate_api_key(tenant_id)

    if not new_key:
        raise HTTPException(status_code=404, detail="Tenant not found")

    return RotateKeyResponse(tenant_id=tenant_id, api_key=new_key)
