"""API key management routes for integrations."""
from __future__ import annotations

import uuid
from typing import List, Optional

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

from normbase.api.deps_auth import RequireInternalToken
from normbase.db.connection import get_db
from normbase.schemas import (
    APIKeyFieldIssueRequest,
    APIKeyIssueRequest,
    APIKeyIssueResponse,
    APIKeyListItem,
    APIKeyResolveRequest,
    APIKeyResolveResponse,
)
from security.auth.api_keys import mask_api_key
from normbase.services.key_service import KeyService

router = APIRouter(prefix="/keys", tags=["keys"])
_key_service = KeyService()


async def _issue_response(
    db: AsyncSession,
    *,
    record,
    plain: str,
) -> APIKeyIssueResponse:
    agent_uuid, field_uuid, org_uuid = await _key_service.resolve_row_metadata(db, row=record)
    kind = record.key_kind if record.key_kind in ("agent", "field") else "agent"
    return APIKeyIssueResponse(
        key_kind=kind,
        key_id=str(record.id),
        agent_id=agent_uuid,
        field_id=field_uuid,
        org_id=org_uuid,
        name=record.name,
        api_key=plain,
        key_preview=mask_api_key(plain),
        scopes=list(record.scopes or []),
        is_active=record.is_active,
        expires_at=record.expires_at,
        created_at=record.created_at,
    )


async def _list_item(db: AsyncSession, *, item) -> APIKeyListItem:
    agent_uuid, field_uuid, org_uuid = await _key_service.resolve_row_metadata(db, row=item)
    kind = item.key_kind if item.key_kind in ("agent", "field") else "agent"
    return APIKeyListItem(
        key_kind=kind,
        key_id=str(item.id),
        agent_id=agent_uuid,
        field_id=field_uuid,
        org_id=org_uuid,
        name=item.name,
        key_preview="***",
        scopes=list(item.scopes or []),
        is_active=item.is_active,
        expires_at=item.expires_at,
        created_at=item.created_at,
    )


@router.post(
    "/issue",
    response_model=APIKeyIssueResponse,
    status_code=status.HTTP_201_CREATED,
    dependencies=[RequireInternalToken],
)
async def issue_api_key(
    request: APIKeyIssueRequest,
    db: AsyncSession = Depends(get_db),
):
    issued = await _key_service.issue_api_key(
        db,
        agent_id=request.agent_id,
        name=request.name,
        expires_at=request.expires_at,
        scopes=request.scopes,
    )
    return await _issue_response(db, record=issued.record, plain=issued.plain_key)


@router.post(
    "/field/issue",
    response_model=APIKeyIssueResponse,
    status_code=status.HTTP_201_CREATED,
    dependencies=[RequireInternalToken],
)
async def issue_field_api_key(
    request: APIKeyFieldIssueRequest,
    db: AsyncSession = Depends(get_db),
):
    issued = await _key_service.issue_field_api_key(
        db,
        field_id=request.field_id,
        name=request.name,
        expires_at=request.expires_at,
        scopes=request.scopes,
    )
    return await _issue_response(db, record=issued.record, plain=issued.plain_key)


@router.get("", response_model=List[APIKeyListItem], dependencies=[RequireInternalToken])
async def list_api_keys(
    agent_id: Optional[uuid.UUID] = Query(None, description="Filter agent keys"),
    field_id: Optional[uuid.UUID] = Query(None, description="Filter field import keys"),
    include_inactive: bool = Query(False),
    db: AsyncSession = Depends(get_db),
):
    if agent_id is not None and field_id is not None:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Specify only one of agent_id or field_id.",
        )
    rows = await _key_service.list_api_keys(
        db,
        agent_id=agent_id,
        field_id=field_id,
        include_inactive=include_inactive,
    )
    return [await _list_item(db, item=r) for r in rows]


@router.post("/{key_id}/revoke", response_model=APIKeyListItem, dependencies=[RequireInternalToken])
async def revoke_api_key(
    key_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
):
    row = await _key_service.revoke_api_key(db, key_id=key_id)
    return await _list_item(db, item=row)


@router.post("/{key_id}/rotate", response_model=APIKeyIssueResponse, dependencies=[RequireInternalToken])
async def rotate_api_key(
    key_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
):
    issued = await _key_service.rotate_api_key(db, key_id=key_id)
    return await _issue_response(db, record=issued.record, plain=issued.plain_key)


@router.post("/resolve", response_model=APIKeyResolveResponse, dependencies=[RequireInternalToken])
async def resolve_api_key(
    request: APIKeyResolveRequest,
    db: AsyncSession = Depends(get_db),
):
    row = await _key_service.resolve_api_key_from_plain(
        db,
        plain_api_key=request.api_key,
    )
    agent_uuid, field_uuid, org_uuid = await _key_service.resolve_row_metadata(db, row=row)
    kind = row.key_kind if row.key_kind in ("agent", "field") else "agent"
    return APIKeyResolveResponse(
        key_id=str(row.id),
        key_kind=kind,
        agent_id=agent_uuid,
        field_id=field_uuid,
        org_id=org_uuid,
        scopes=list(row.scopes or []),
        is_active=row.is_active,
        expires_at=row.expires_at,
    )


@router.get("/introspect", response_model=APIKeyResolveResponse)
async def introspect_api_key(
    authorization: Optional[str] = Header(default=None),
    x_api_key: Optional[str] = Header(default=None),
    db: AsyncSession = Depends(get_db),
):
    plain = (x_api_key or "").strip() or _key_service.extract_bearer(authorization)
    if not plain:
        raise HTTPException(status_code=401, detail="Missing API key")
    row = await _key_service.resolve_api_key_from_plain(db, plain_api_key=plain)
    agent_uuid, field_uuid, org_uuid = await _key_service.resolve_row_metadata(db, row=row)
    kind = row.key_kind if row.key_kind in ("agent", "field") else "agent"
    return APIKeyResolveResponse(
        key_id=str(row.id),
        key_kind=kind,
        agent_id=agent_uuid,
        field_id=field_uuid,
        org_id=org_uuid,
        scopes=list(row.scopes or []),
        is_active=row.is_active,
        expires_at=row.expires_at,
    )
