"""Tests for the StorageClient."""

import pytest
import respx
from httpx import Response

from kamimind_storage import StorageClient
from kamimind_storage.exceptions import AuthenticationError, NotFoundError


class TestStorageClient:
    """Tests for StorageClient."""

    def test_init(self, base_url: str, access_token: str) -> None:
        """Test client initialization."""
        client = StorageClient(base_url=base_url, access_token=access_token)
        assert client is not None
        client.close()

    def test_context_manager(self, base_url: str, access_token: str) -> None:
        """Test client as context manager."""
        with StorageClient(base_url=base_url, access_token=access_token) as client:
            assert client is not None

    @respx.mock
    def test_upload_bytes_success(self, client: StorageClient, session_id: str) -> None:
        """Test uploading bytes successfully."""
        # Mock initiate
        respx.post("https://storage.example.com/api/v2/storage/upload/initiate").mock(
            return_value=Response(
                200,
                json={
                    "success": True,
                    "result": {
                        "sessionId": session_id,
                        "uploadUrl": "https://r2.example.com/presigned",
                    },
                },
            )
        )

        # Mock presigned upload
        respx.put("https://r2.example.com/presigned").mock(return_value=Response(200))

        # Mock complete
        respx.post(f"https://storage.example.com/api/v2/storage/upload/{session_id}/complete").mock(
            return_value=Response(
                200,
                json={
                    "success": True,
                    "result": {
                        "sessionId": session_id,
                        "objectKey": "uploads/user/test.txt",
                        "fileName": "test.txt",
                        "fileSize": 13,
                        "uploadedSize": 13,
                        "contentType": "text/plain",
                        "status": "completed",
                        "isPublic": False,
                        "completedParts": [],
                        "createdAt": "2024-01-01T00:00:00Z",
                    },
                },
            )
        )

        # Mock status endpoint (called after complete)
        respx.get(f"https://storage.example.com/api/v2/storage/upload/{session_id}/status").mock(
            return_value=Response(
                200,
                json={
                    "success": True,
                    "result": {
                        "sessionId": session_id,
                        "objectKey": "uploads/user/test.txt",
                        "fileName": "test.txt",
                        "fileSize": 13,
                        "uploadedSize": 13,
                        "contentType": "text/plain",
                        "status": "completed",
                        "isPublic": False,
                        "completedParts": [],
                        "createdAt": "2024-01-01T00:00:00Z",
                    },
                },
            )
        )

        result = client.upload_bytes(b"Hello, World!", filename="test.txt")

        assert result.session_id == session_id
        assert result.status.value == "completed"

    @respx.mock
    def test_authentication_error(self, client: StorageClient) -> None:
        """Test authentication error handling."""
        respx.post("https://storage.example.com/api/v2/storage/upload/initiate").mock(
            return_value=Response(
                401,
                json={"success": False, "error": "Unauthorized"},
            )
        )

        with pytest.raises(AuthenticationError):
            client.upload_bytes(b"test", filename="test.txt")

    @respx.mock
    def test_get_upload_status(self, client: StorageClient, session_id: str) -> None:
        """Test getting upload status."""
        respx.get(f"https://storage.example.com/api/v2/storage/upload/{session_id}/status").mock(
            return_value=Response(
                200,
                json={
                    "success": True,
                    "result": {
                        "sessionId": session_id,
                        "objectKey": "uploads/user/test.txt",
                        "fileName": "test.txt",
                        "fileSize": 100,
                        "uploadedSize": 50,
                        "contentType": "text/plain",
                        "status": "uploading",
                        "isPublic": False,
                        "completedParts": [1],
                        "totalParts": 2,
                        "createdAt": "2024-01-01T00:00:00Z",
                    },
                },
            )
        )

        result = client.get_upload_status(session_id)

        assert result.session_id == session_id
        assert result.status.value == "uploading"

    @respx.mock
    def test_get_download_url(self, client: StorageClient, session_id: str) -> None:
        """Test getting download URL."""
        respx.get(f"https://storage.example.com/api/v2/storage/upload/{session_id}/download").mock(
            return_value=Response(
                200,
                json={
                    "success": True,
                    "result": {
                        "downloadUrl": "https://r2.example.com/download",
                        "fileName": "test.txt",
                        "fileSize": 100,
                        "contentType": "text/plain",
                    },
                },
            )
        )

        result = client.get_download_url(session_id)

        assert result.download_url == "https://r2.example.com/download"
        assert result.file_name == "test.txt"

    @respx.mock
    def test_make_public(self, client: StorageClient, session_id: str) -> None:
        """Test making a file public."""
        respx.post(
            f"https://storage.example.com/api/v2/storage/upload/{session_id}/make-public"
        ).mock(
            return_value=Response(
                200,
                json={
                    "success": True,
                    "result": {
                        "sessionId": session_id,
                        "publicUrl": "https://storage.example.com/api/v2/storage/upload/public/abc12345",
                        "shortcut": "abc12345",
                        "isPublic": True,
                    },
                },
            )
        )

        result = client.make_public(session_id)

        assert result.is_public is True
        assert result.shortcut == "abc12345"

    @respx.mock
    def test_not_found_error(self, client: StorageClient, session_id: str) -> None:
        """Test not found error handling."""
        respx.get(f"https://storage.example.com/api/v2/storage/upload/{session_id}/status").mock(
            return_value=Response(
                404,
                json={"success": False, "error": "Session not found"},
            )
        )

        with pytest.raises(NotFoundError):
            client.get_upload_status(session_id)

    def test_get_public_url(self, client: StorageClient) -> None:
        """Test generating public URL."""
        url = client.get_public_url("abc12345")
        assert url == "https://storage.example.com/api/v2/storage/upload/public/abc12345"
