"""Tests for the Loom API client.

Generated by GRIMLOCK MCP Factory
"""

import httpx
import pytest
import respx

from loom_mcp.clients.loom import LoomClient


class TestLoomClientInit:
    """Tests for LoomClient initialization."""

    def test_init_with_defaults(self, mock_env: None) -> None:
        """Test client initializes with environment variables."""
        client = LoomClient()
        assert client.access_token == "test-access-token-12345"
        assert client.base_url == "https://api.loom.com/v1"

    def test_init_with_custom_values(self) -> None:
        """Test client initializes with custom values."""
        client = LoomClient(
            access_token="custom-token",
            base_url="https://custom.api.loom.com/v1/",
        )
        assert client.access_token == "custom-token"
        assert client.base_url == "https://custom.api.loom.com/v1"

    def test_init_strips_trailing_slash(self) -> None:
        """Test that base URL trailing slash is stripped."""
        client = LoomClient(
            access_token="token",
            base_url="https://api.loom.com/v1///",
        )
        assert client.base_url == "https://api.loom.com/v1"


class TestLoomClientHeaders:
    """Tests for LoomClient headers."""

    def test_get_headers(self, mock_env: None) -> None:
        """Test headers include Bearer token."""
        client = LoomClient()
        headers = client._get_headers()

        assert headers["Authorization"] == "Bearer test-access-token-12345"
        assert headers["Content-Type"] == "application/json"
        assert headers["Accept"] == "application/json"


class TestLoomClientListVideos:
    """Tests for LoomClient.list_videos."""

    @pytest.mark.asyncio
    async def test_list_videos_success(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_videos_response: dict,
    ) -> None:
        """Test successful video listing."""
        mock_httpx_client.get("https://api.loom.com/v1/videos").mock(
            return_value=httpx.Response(200, json=sample_videos_response)
        )

        client = LoomClient()
        result = await client.list_videos()

        assert "videos" in result
        assert len(result["videos"]) == 3
        assert result["total"] == 3

    @pytest.mark.asyncio
    async def test_list_videos_with_pagination(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_videos_response: dict,
    ) -> None:
        """Test video listing with pagination parameters."""
        mock_httpx_client.get("https://api.loom.com/v1/videos").mock(
            return_value=httpx.Response(200, json=sample_videos_response)
        )

        client = LoomClient()
        result = await client.list_videos(limit=10, offset=20)

        assert "videos" in result

    @pytest.mark.asyncio
    async def test_list_videos_with_folder_filter(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_videos_response: dict,
    ) -> None:
        """Test video listing with folder filter."""
        mock_httpx_client.get("https://api.loom.com/v1/videos").mock(
            return_value=httpx.Response(200, json=sample_videos_response)
        )

        client = LoomClient()
        result = await client.list_videos(folder_id="folder-abc")

        assert "videos" in result

    @pytest.mark.asyncio
    async def test_list_videos_empty(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_empty_videos_response: dict,
    ) -> None:
        """Test empty video list response."""
        mock_httpx_client.get("https://api.loom.com/v1/videos").mock(
            return_value=httpx.Response(200, json=sample_empty_videos_response)
        )

        client = LoomClient()
        result = await client.list_videos()

        assert result["videos"] == []
        assert result["total"] == 0

    @pytest.mark.asyncio
    async def test_list_videos_handles_list_response(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
    ) -> None:
        """Test that list response is normalized."""
        raw_list = [{"id": "v1"}, {"id": "v2"}]
        mock_httpx_client.get("https://api.loom.com/v1/videos").mock(
            return_value=httpx.Response(200, json=raw_list)
        )

        client = LoomClient()
        result = await client.list_videos()

        assert "videos" in result
        assert len(result["videos"]) == 2

    @pytest.mark.asyncio
    async def test_list_videos_auth_error(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
    ) -> None:
        """Test authentication error handling."""
        mock_httpx_client.get("https://api.loom.com/v1/videos").mock(
            return_value=httpx.Response(401, json={"error": "Unauthorized"})
        )

        client = LoomClient()
        with pytest.raises(httpx.HTTPStatusError):
            await client.list_videos()


class TestLoomClientGetVideo:
    """Tests for LoomClient.get_video."""

    @pytest.mark.asyncio
    async def test_get_video_success(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_video_detail_response: dict,
    ) -> None:
        """Test successful video retrieval."""
        mock_httpx_client.get("https://api.loom.com/v1/videos/video-123").mock(
            return_value=httpx.Response(200, json=sample_video_detail_response)
        )

        client = LoomClient()
        result = await client.get_video("video-123")

        assert result["id"] == "video-123"
        assert result["title"] == "Product Demo"
        assert result["duration"] == 120

    @pytest.mark.asyncio
    async def test_get_video_not_found(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
    ) -> None:
        """Test video not found error."""
        mock_httpx_client.get("https://api.loom.com/v1/videos/nonexistent").mock(
            return_value=httpx.Response(404, json={"error": "Not found"})
        )

        client = LoomClient()
        with pytest.raises(httpx.HTTPStatusError):
            await client.get_video("nonexistent")


class TestLoomClientEditVideo:
    """Tests for LoomClient.edit_video."""

    @pytest.mark.asyncio
    async def test_edit_video_trim(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_edit_response: dict,
    ) -> None:
        """Test video trimming."""
        mock_httpx_client.post("https://api.loom.com/v1/videos/video-123/edit").mock(
            return_value=httpx.Response(200, json=sample_edit_response)
        )

        client = LoomClient()
        result = await client.edit_video(
            video_id="video-123",
            editing_details={"trim_start": 5, "trim_end": 100},
        )

        assert result["job_id"] == "edit-job-001"
        assert result["status"] == "processing"

    @pytest.mark.asyncio
    async def test_edit_video_with_clips(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_edit_response: dict,
    ) -> None:
        """Test video editing with clips."""
        mock_httpx_client.post("https://api.loom.com/v1/videos/video-123/edit").mock(
            return_value=httpx.Response(200, json=sample_edit_response)
        )

        client = LoomClient()
        result = await client.edit_video(
            video_id="video-123",
            editing_details={
                "clips": [
                    {"start": 0, "end": 30},
                    {"start": 60, "end": 90},
                ]
            },
        )

        assert result["status"] == "processing"


class TestLoomClientMergeVideos:
    """Tests for LoomClient.merge_videos."""

    @pytest.mark.asyncio
    async def test_merge_videos_success(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_merge_response: dict,
    ) -> None:
        """Test successful video merge."""
        mock_httpx_client.post("https://api.loom.com/v1/videos/merge").mock(
            return_value=httpx.Response(200, json=sample_merge_response)
        )

        client = LoomClient()
        result = await client.merge_videos(
            video_ids=["video-123", "video-456"],
            title="Merged Video",
        )

        assert result["job_id"] == "merge-job-001"
        assert result["status"] == "processing"
        assert result["source_videos"] == ["video-123", "video-456"]

    @pytest.mark.asyncio
    async def test_merge_videos_without_title(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_merge_response: dict,
    ) -> None:
        """Test video merge without custom title."""
        mock_httpx_client.post("https://api.loom.com/v1/videos/merge").mock(
            return_value=httpx.Response(200, json=sample_merge_response)
        )

        client = LoomClient()
        result = await client.merge_videos(video_ids=["video-123", "video-456"])

        assert result["status"] == "processing"


class TestLoomClientUpdateVideo:
    """Tests for LoomClient.update_video."""

    @pytest.mark.asyncio
    async def test_update_video_title(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_video_detail_response: dict,
    ) -> None:
        """Test updating video title."""
        updated = sample_video_detail_response.copy()
        updated["title"] = "New Title"

        mock_httpx_client.patch("https://api.loom.com/v1/videos/video-123").mock(
            return_value=httpx.Response(200, json=updated)
        )

        client = LoomClient()
        result = await client.update_video("video-123", title="New Title")

        assert result["title"] == "New Title"


class TestLoomClientDeleteVideo:
    """Tests for LoomClient.delete_video."""

    @pytest.mark.asyncio
    async def test_delete_video_success(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
    ) -> None:
        """Test successful video deletion."""
        mock_httpx_client.delete("https://api.loom.com/v1/videos/video-123").mock(
            return_value=httpx.Response(204)
        )

        client = LoomClient()
        result = await client.delete_video("video-123")

        assert result == {}


class TestLoomClientFolders:
    """Tests for LoomClient folder operations."""

    @pytest.mark.asyncio
    async def test_list_folders(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_folders_response: dict,
    ) -> None:
        """Test listing folders."""
        mock_httpx_client.get("https://api.loom.com/v1/folders").mock(
            return_value=httpx.Response(200, json=sample_folders_response)
        )

        client = LoomClient()
        result = await client.list_folders()

        assert "folders" in result
        assert len(result["folders"]) == 2

    @pytest.mark.asyncio
    async def test_get_folder(
        self,
        mock_env: None,
        mock_httpx_client: respx.MockRouter,
        sample_folder_response: dict,
    ) -> None:
        """Test getting a specific folder."""
        mock_httpx_client.get("https://api.loom.com/v1/folders/folder-abc").mock(
            return_value=httpx.Response(200, json=sample_folder_response)
        )

        client = LoomClient()
        result = await client.get_folder("folder-abc")

        assert result["id"] == "folder-abc"
        assert result["name"] == "Product Videos"
