from datetime import datetime
from uuid import UUID
import hashlib
import secrets

from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession

from src.core.exceptions import ConflictException, NotFoundException
from src.domain.entities import APIClientEntity, APIKeyEntity
from src.infrastructure.database.repositories import APIClientRepository, APIKeyRepository
from src.infrastructure.database.session import get_db_session
from src.api.v1.dependencies.auth import get_current_user, require_role
from src.domain.entities import UserRole
from src.services.auth.security import TokenData, generate_api_key

router = APIRouter(prefix="/api-clients", tags=["API Clients"])


class APIClientCreateRequest(BaseModel):
    name: str = Field(..., min_length=1, max_length=255)
    description: str | None = None
    scopes: list[str] = Field(default_factory=lambda: ["pharmacies:read", "medications:read", "inventory:read"])
    rate_limit: int | None = None
    allowed_ips: list[str] = Field(default_factory=list)


class APIClientResponse(BaseModel):
    id: UUID
    name: str
    description: str | None
    owner_id: UUID | None
    is_active: bool
    scopes: list[str]
    rate_limit: int | None
    allowed_ips: list[str]
    created_at: datetime | None
    updated_at: datetime | None


class APIKeyCreateRequest(BaseModel):
    name: str = Field(..., min_length=1, max_length=255)
    expires_at: datetime | None = None


class APIKeyResponse(BaseModel):
    id: UUID
    name: str
    key_prefix: str
    is_active: bool
    expires_at: datetime | None
    last_used_at: datetime | None
    created_at: datetime | None


class APIKeyCreateResponse(BaseModel):
    id: UUID
    name: str
    key: str
    key_prefix: str
    expires_at: datetime | None


class APIClientListResponse(BaseModel):
    items: list[APIClientResponse]
    total: int
    offset: int
    limit: int


@router.get("", response_model=APIClientListResponse)
async def list_api_clients(
    is_active: bool | None = None,
    offset: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    session: AsyncSession = Depends(get_db_session),
    current_user: TokenData = Depends(require_role(UserRole.ADMIN)),
):
    repo = APIClientRepository(session)
    entities, total = await repo.list_clients(is_active=is_active, offset=offset, limit=limit)
    items = [
        APIClientResponse(
            id=e.id, name=e.name, description=e.description, owner_id=e.owner_id,
            is_active=e.is_active, scopes=e.scopes, rate_limit=e.rate_limit,
            allowed_ips=e.allowed_ips, created_at=e.created_at, updated_at=e.updated_at,
        )
        for e in entities
    ]
    return APIClientListResponse(items=items, total=total, offset=offset, limit=limit)


@router.post("", response_model=APIClientResponse, status_code=201)
async def create_api_client(
    body: APIClientCreateRequest,
    session: AsyncSession = Depends(get_db_session),
    current_user: TokenData = Depends(require_role(UserRole.ADMIN)),
):
    repo = APIClientRepository(session)
    entity = APIClientEntity(
        name=body.name, description=body.description,
        owner_id=UUID(current_user.subject), is_active=True,
        scopes=body.scopes, rate_limit=body.rate_limit,
        allowed_ips=body.allowed_ips,
    )
    created = await repo.create(entity)
    return APIClientResponse(
        id=created.id, name=created.name, description=created.description,
        owner_id=created.owner_id, is_active=created.is_active,
        scopes=created.scopes, rate_limit=created.rate_limit,
        allowed_ips=created.allowed_ips, created_at=created.created_at,
        updated_at=created.updated_at,
    )


@router.post("/{client_id}/keys", response_model=APIKeyCreateResponse, status_code=201)
async def create_api_key(
    client_id: UUID,
    body: APIKeyCreateRequest,
    session: AsyncSession = Depends(get_db_session),
    current_user: TokenData = Depends(require_role(UserRole.ADMIN)),
):
    client_repo = APIClientRepository(session)
    client = await client_repo.get_by_id(client_id)
    if not client:
        raise NotFoundException("API Client", str(client_id))

    raw_key, prefix, key_hash = generate_api_key()
    key_repo = APIKeyRepository(session)
    key_entity = APIKeyEntity(
        api_client_id=client_id, key_prefix=prefix,
        key_hash=key_hash, name=body.name,
        is_active=True, expires_at=body.expires_at,
    )
    created = await key_repo.create(key_entity)
    return APIKeyCreateResponse(
        id=created.id, name=created.name, key=raw_key,
        key_prefix=created.key_prefix, expires_at=created.expires_at,
    )


@router.get("/{client_id}/keys", response_model=list[APIKeyResponse])
async def list_api_keys(
    client_id: UUID,
    session: AsyncSession = Depends(get_db_session),
    current_user: TokenData = Depends(require_role(UserRole.ADMIN)),
):
    key_repo = APIKeyRepository(session)
    keys = await key_repo.list_by_client(client_id)
    return [
        APIKeyResponse(
            id=k.id, name=k.name, key_prefix=k.key_prefix,
            is_active=k.is_active, expires_at=k.expires_at,
            last_used_at=k.last_used_at, created_at=k.created_at,
        )
        for k in keys
    ]
