from typing import List

from fastapi import APIRouter, Depends, HTTPException, status

from app.api.deps import RequestContext, get_request_context
from app.models.api_keys import (
    ApiKeyCreateRequest,
    ApiKeyCreateResponse,
    ApiKeyRecord,
    ApiKeyRevokeRequest,
    ApiKeyToggleRequest,
)
from app.services import api_keys
from app.services.exceptions import ForbiddenError, NotFoundError, ValidationError

router = APIRouter()


def _to_record(payload: dict) -> ApiKeyRecord:
    return ApiKeyRecord(**payload)


@router.get("", response_model=List[ApiKeyRecord])
async def list_api_keys(
    ctx: RequestContext = Depends(get_request_context),
) -> List[ApiKeyRecord]:
    records = api_keys.list_api_keys(ctx.user_id)
    return [_to_record(record) for record in records]


@router.post("", response_model=ApiKeyCreateResponse, status_code=status.HTTP_201_CREATED)
async def create_api_key(
    payload: ApiKeyCreateRequest,
    ctx: RequestContext = Depends(get_request_context),
) -> ApiKeyCreateResponse:
    try:
        result = api_keys.generate_api_key(
            user_id=ctx.user_id,
            name=payload.name,
            description=payload.description,
        )
        return ApiKeyCreateResponse(
            key=result["key"],
            record=_to_record(result["record"]),
        )
    except ValidationError as exc:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc


@router.post("/toggle", status_code=status.HTTP_204_NO_CONTENT)
async def toggle_api_key(
    payload: ApiKeyToggleRequest,
    ctx: RequestContext = Depends(get_request_context),
) -> None:
    try:
        api_keys.toggle_api_key(ctx.user_id, payload.key_id, payload.active)
    except NotFoundError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
    except ForbiddenError as exc:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(exc)) from exc


@router.post("/revoke", status_code=status.HTTP_204_NO_CONTENT)
async def revoke_api_key(
    payload: ApiKeyRevokeRequest,
    ctx: RequestContext = Depends(get_request_context),
) -> None:
    try:
        api_keys.revoke_api_key(ctx.user_id, payload.key_id)
    except NotFoundError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
    except ForbiddenError as exc:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(exc)) from exc
