from __future__ import annotations

from typing import List, Optional
from uuid import UUID

from .http import HttpClient, AsyncHttpClient
from .types import (
    StorageUploadRequest,
    StorageUploadResponse,
    StorageConfirmRequest,
    StorageDownloadRequest,
    StorageDownloadResponse,
    StorageObjectOut,
    StorageDeleteResponse,
    StoragePrivacyRequest,
    FolderCreateRequest,
    FolderOut,
    FolderDeleteResponse,
)

class StorageClient:
    """Storage API (API key)."""
    def __init__(self, http: HttpClient):
        self._http = http

    def create_upload_url(
        self,
        *,
        filename: str,
        content_type: str,
        size_bytes: int,
        folder_id: Optional[UUID] = None,
        is_public: bool = False,
        generate_thumbnail: bool = False,
        transcode_preset: str = "none",
    ) -> StorageUploadResponse:
        payload = StorageUploadRequest(
            filename=filename,
            content_type=content_type,
            size_bytes=size_bytes,
            folder_id=folder_id,
            is_public=is_public,
            generate_thumbnail=generate_thumbnail,
            transcode_preset=transcode_preset,
        )
        data = self._http.post("/storage/upload-url/api", json=payload.model_dump(mode="json", exclude_none=True))
        return StorageUploadResponse.model_validate(data)

    def confirm_upload(self, *, object_id: UUID) -> StorageObjectOut:
        payload = StorageConfirmRequest(object_id=object_id)
        data = self._http.post("/storage/confirm/api", json=payload.model_dump(mode="json"))
        return StorageObjectOut.model_validate(data)

    def create_download_url(self, *, object_id: UUID) -> StorageDownloadResponse:
        payload = StorageDownloadRequest(object_id=object_id)
        data = self._http.post("/storage/download-url/api", json=payload.model_dump(mode="json"))
        return StorageDownloadResponse.model_validate(data)

    def list_objects(self, *, folder_id: Optional[UUID] = None) -> List[StorageObjectOut]:
        params = {"folder_id": str(folder_id)} if folder_id else None
        data = self._http.get("/storage/list/api", params=params)
        return [StorageObjectOut.model_validate(x) for x in (data or [])]

    def set_object_public(self, *, object_id: UUID, is_public: bool) -> StorageObjectOut:
        payload = StoragePrivacyRequest(is_public=is_public)
        data = self._http.patch(f"/storage/object/api/{object_id}/privacy", json=payload.model_dump())
        return StorageObjectOut.model_validate(data)

    def delete_object(self, *, object_id: UUID) -> StorageDeleteResponse:
        data = self._http.delete(f"/storage/object/api/{object_id}")
        return StorageDeleteResponse.model_validate(data)

    def create_folder(self, *, path: str) -> FolderOut:
        payload = FolderCreateRequest(path=path)
        data = self._http.post("/storage/folders/api", json=payload.model_dump())
        return FolderOut.model_validate(data)

    def list_folders(self) -> List[FolderOut]:
        data = self._http.get("/storage/folders/api")
        return [FolderOut.model_validate(x) for x in (data or [])]

    def delete_folder(self, *, folder_id: UUID) -> FolderDeleteResponse:
        data = self._http.delete(f"/storage/folders/api/{folder_id}")
        return FolderDeleteResponse.model_validate(data)


class AsyncStorageClient:
    def __init__(self, http: AsyncHttpClient):
        self._http = http

    async def create_upload_url(
        self,
        *,
        filename: str,
        content_type: str,
        size_bytes: int,
        folder_id: Optional[UUID] = None,
        is_public: bool = False,
        generate_thumbnail: bool = False,
        transcode_preset: str = "none",
    ) -> StorageUploadResponse:
        payload = StorageUploadRequest(
            filename=filename,
            content_type=content_type,
            size_bytes=size_bytes,
            folder_id=folder_id,
            is_public=is_public,
            generate_thumbnail=generate_thumbnail,
            transcode_preset=transcode_preset,
        )
        data = await self._http.post("/storage/upload-url/api", json=payload.model_dump(exclude_none=True))
        return StorageUploadResponse.model_validate(data)

    async def confirm_upload(self, *, object_id: UUID) -> StorageObjectOut:
        payload = StorageConfirmRequest(object_id=object_id)
        data = await self._http.post("/storage/confirm/api", json=payload.model_dump(mode="json"))
        return StorageObjectOut.model_validate(data)

    async def create_download_url(self, *, object_id: UUID) -> StorageDownloadResponse:
        payload = StorageDownloadRequest(object_id=object_id)
        data = await self._http.post("/storage/download-url/api", json=payload.model_dump())
        return StorageDownloadResponse.model_validate(data)

    async def list_objects(self, *, folder_id: Optional[UUID] = None) -> List[StorageObjectOut]:
        params = {"folder_id": str(folder_id)} if folder_id else None
        data = await self._http.get("/storage/list/api", params=params)
        return [StorageObjectOut.model_validate(x) for x in (data or [])]

    async def set_object_public(self, *, object_id: UUID, is_public: bool) -> StorageObjectOut:
        payload = StoragePrivacyRequest(is_public=is_public)
        data = await self._http.patch(f"/storage/object/api/{object_id}/privacy", json=payload.model_dump())
        return StorageObjectOut.model_validate(data)

    async def delete_object(self, *, object_id: UUID) -> StorageDeleteResponse:
        data = await self._http.delete(f"/storage/object/api/{object_id}")
        return StorageDeleteResponse.model_validate(data)

    async def create_folder(self, *, path: str) -> FolderOut:
        payload = FolderCreateRequest(path=path)
        data = await self._http.post("/storage/folders/api", json=payload.model_dump())
        return FolderOut.model_validate(data)

    async def list_folders(self) -> List[FolderOut]:
        data = await self._http.get("/storage/folders/api")
        return [FolderOut.model_validate(x) for x in (data or [])]

    async def delete_folder(self, *, folder_id: UUID) -> FolderDeleteResponse:
        data = await self._http.delete(f"/storage/folders/api/{folder_id}")
        return FolderDeleteResponse.model_validate(data)
