"""Tests for Platform2StepClient."""

import pytest
import respx
from httpx import Response

from platform_2step_mcp.client import (
    BatchResponse,
    PendingOperationResponse,
    Platform2StepClient,
)


class TestListCategories:
    """Tests for list_categories."""

    async def test_list_categories_success(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_categories_response: dict,
    ):
        """Test successful category listing."""
        mock_api.get("/api/v1/categories").mock(
            return_value=Response(200, json=sample_categories_response)
        )

        result = await client.list_categories(company_id=1238)

        assert result == sample_categories_response
        assert len(result["data"]) == 1
        assert result["data"][0]["name"] == "Cortes de Pelo"

    async def test_list_categories_with_pagination(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_categories_response: dict,
    ):
        """Test category listing with pagination parameters."""
        mock_api.get("/api/v1/categories").mock(
            return_value=Response(200, json=sample_categories_response)
        )

        result = await client.list_categories(company_id=1238, page=2, per_page=10)

        assert result == sample_categories_response
        request = mock_api.calls.last.request
        assert "page=2" in str(request.url)
        assert "per_page=10" in str(request.url)

    async def test_list_categories_sends_company_id_as_query_param(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_categories_response: dict,
    ):
        """Test that list_categories sends company_id as query parameter."""
        mock_api.get("/api/v1/categories").mock(
            return_value=Response(200, json=sample_categories_response)
        )

        await client.list_categories(company_id=9479)

        request = mock_api.calls.last.request
        assert "company_id=9479" in str(request.url)
        assert "X-Company-Id" not in request.headers


class TestGetCategory:
    """Tests for get_category."""

    async def test_get_category_success(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_category: dict,
    ):
        """Test successful category retrieval."""
        mock_api.get("/api/v1/categories/123").mock(
            return_value=Response(200, json=sample_category)
        )

        result = await client.get_category(category_id=123)

        assert result == sample_category
        assert result["id"] == 123

    async def test_get_category_no_company_id_needed(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_category: dict,
    ):
        """Test that get_category does not require company_id."""
        mock_api.get("/api/v1/categories/123").mock(
            return_value=Response(200, json=sample_category)
        )

        await client.get_category(category_id=123)

        request = mock_api.calls.last.request
        assert "X-Company-Id" not in request.headers
        assert "company_id" not in str(request.url)


class TestCreateBatch:
    """Tests for create_batch."""

    async def test_create_batch_success(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_batch_response: dict,
    ):
        """Test successful batch creation."""
        mock_api.post("/api/v1/batches").mock(
            return_value=Response(202, json=sample_batch_response)
        )

        operations = [
            {"operation": "create", "resource": "category", "payload": {"name": "Cat1"}},
            {"operation": "create", "resource": "category", "payload": {"name": "Cat2"}},
            {"operation": "create", "resource": "category", "payload": {"name": "Cat3"}},
        ]

        result = await client.create_batch(
            operations=operations, company_id=1238, description="Import categories"
        )

        assert isinstance(result, BatchResponse)
        assert result.batch_id == "batch-123-456"
        assert result.operations_count == 3
        assert result.status == "pending"

    async def test_create_batch_sends_company_id_as_query_param(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_batch_response: dict,
    ):
        """Test that create_batch sends company_id as query parameter."""
        mock_api.post("/api/v1/batches").mock(
            return_value=Response(202, json=sample_batch_response)
        )

        operations = [
            {"operation": "create", "resource": "category", "payload": {"name": "Cat1"}},
        ]

        await client.create_batch(operations=operations, company_id=9479)

        request = mock_api.calls.last.request
        assert "company_id=9479" in str(request.url)
        assert "X-Company-Id" not in request.headers


class TestGetBatchStatus:
    """Tests for get_batch_status."""

    async def test_get_batch_status_success(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_batch_response: dict,
    ):
        """Test getting batch status."""
        mock_api.get("/api/v1/batches/batch-123-456").mock(
            return_value=Response(200, json=sample_batch_response)
        )

        result = await client.get_batch_status("batch-123-456")

        assert isinstance(result, BatchResponse)
        assert result.status == "pending"
        assert len(result.operations) == 3

    async def test_get_batch_status_no_company_id_needed(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_batch_response: dict,
    ):
        """Test that get_batch_status does not require company_id."""
        mock_api.get("/api/v1/batches/batch-123-456").mock(
            return_value=Response(200, json=sample_batch_response)
        )

        await client.get_batch_status("batch-123-456")

        request = mock_api.calls.last.request
        assert "X-Company-Id" not in request.headers


class TestServices:
    """Tests for service operations."""

    async def test_list_services(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_service: dict,
    ):
        """Test listing services."""
        response = {"data": [sample_service]}
        mock_api.get("/api/v1/services").mock(
            return_value=Response(200, json=response)
        )

        result = await client.list_services(company_id=1238)

        assert result["data"][0]["name"] == "Corte de Pelo"

    async def test_list_services_sends_company_id_as_query_param(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_service: dict,
    ):
        """Test that list_services sends company_id as query parameter."""
        response = {"data": [sample_service]}
        mock_api.get("/api/v1/services").mock(
            return_value=Response(200, json=response)
        )

        await client.list_services(company_id=9479)

        request = mock_api.calls.last.request
        assert "company_id=9479" in str(request.url)
        assert "X-Company-Id" not in request.headers

    async def test_list_services_with_service_category_id(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_service: dict,
    ):
        """Test that list_services sends service_category_id as query parameter."""
        response = {"data": [sample_service]}
        mock_api.get("/api/v1/services").mock(
            return_value=Response(200, json=response)
        )

        await client.list_services(company_id=1238, service_category_id=42)

        request = mock_api.calls.last.request
        assert "service_category_id=42" in str(request.url)

    async def test_get_service_no_company_id_needed(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_service: dict,
    ):
        """Test that get_service does not require company_id."""
        mock_api.get("/api/v1/services/456").mock(
            return_value=Response(200, json=sample_service)
        )

        await client.get_service(service_id=456)

        request = mock_api.calls.last.request
        assert "X-Company-Id" not in request.headers

class TestBookings:
    """Tests for booking operations."""

    async def test_list_bookings(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_booking: dict,
    ):
        """Test listing bookings."""
        response = {"data": [sample_booking]}
        mock_api.get("/api/v1/bookings").mock(
            return_value=Response(200, json=response)
        )

        result = await client.list_bookings(
            company_id=1238, start_date="2024-01-15", end_date="2024-01-16"
        )

        assert result["data"][0]["id"] == 789

    async def test_list_bookings_sends_company_id_as_query_param(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_booking: dict,
    ):
        """Test that list_bookings sends company_id as query parameter."""
        response = {"data": [sample_booking]}
        mock_api.get("/api/v1/bookings").mock(
            return_value=Response(200, json=response)
        )

        await client.list_bookings(
            company_id=9479, start_date="2024-01-15", end_date="2024-01-16"
        )

        request = mock_api.calls.last.request
        assert "company_id=9479" in str(request.url)
        assert "X-Company-Id" not in request.headers

    async def test_list_bookings_with_location_id(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_booking: dict,
    ):
        """Test that list_bookings sends location_id as query parameter."""
        response = {"data": [sample_booking]}
        mock_api.get("/api/v1/bookings").mock(
            return_value=Response(200, json=response)
        )

        await client.list_bookings(
            company_id=1238, start_date="2024-01-15", end_date="2024-01-16",
            location_id=7,
        )

        request = mock_api.calls.last.request
        assert "location_id=7" in str(request.url)

    async def test_list_bookings_with_status_id(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_booking: dict,
    ):
        """Test that list_bookings sends status_id as integer query parameter."""
        response = {"data": [sample_booking]}
        mock_api.get("/api/v1/bookings").mock(
            return_value=Response(200, json=response)
        )

        await client.list_bookings(
            company_id=1238, start_date="2024-01-15", end_date="2024-01-16",
            status_id=2,
        )

        request = mock_api.calls.last.request
        assert "status_id=2" in str(request.url)

    async def test_get_booking_no_company_id_needed(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
        sample_booking: dict,
    ):
        """Test that get_booking does not require company_id."""
        mock_api.get("/api/v1/bookings/789").mock(
            return_value=Response(200, json=sample_booking)
        )

        await client.get_booking(booking_id=789)

        request = mock_api.calls.last.request
        assert "X-Company-Id" not in request.headers

    async def test_create_booking(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test creating a booking."""
        response = {
            "confirmation_id": "bkg-123",
            "operation": "create",
            "resource": "booking",
            "preview": {
                "service_id": 456,
                "provider_id": 10,
                "start": "2024-01-15T10:00:00Z",
            },
            "expires_at": "2024-01-15T10:05:00Z",
            "confirm_url": "/api/v1/confirmations/bkg-123",
        }
        mock_api.post("/api/v1/bookings").mock(
            return_value=Response(202, json=response)
        )

        result = await client.create_booking(
            service_id=456,
            provider_id=10,
            client_id=20,
            start_time="2024-01-15T10:00:00Z",
            company_id=1238,
            location_id=1,
        )

        assert result.confirmation_id == "bkg-123"
        assert result.resource == "booking"

    async def test_create_booking_sends_company_id_in_body(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test that create_booking sends company_id in request body."""
        response = {
            "confirmation_id": "bkg-123",
            "operation": "create",
            "resource": "booking",
            "preview": {},
            "expires_at": "2024-01-15T10:05:00Z",
            "confirm_url": "/api/v1/confirmations/bkg-123",
        }
        mock_api.post("/api/v1/bookings").mock(
            return_value=Response(202, json=response)
        )

        await client.create_booking(
            service_id=456,
            provider_id=10,
            client_id=20,
            start_time="2024-01-15T10:00:00Z",
            company_id=9479,
            location_id=1,
        )

        request = mock_api.calls.last.request
        import json

        body = json.loads(request.content)
        assert body["company_id"] == 9479
        assert "X-Company-Id" not in request.headers

    async def test_cancel_booking_no_company_id_needed(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test that cancel_booking does not require company_id."""
        response = {
            "confirmation_id": "cancel-123",
            "operation": "delete",
            "resource": "booking",
            "resource_id": 789,
            "preview": None,
            "expires_at": "2024-01-15T10:05:00Z",
            "confirm_url": "/api/v1/confirmations/cancel-123",
        }
        mock_api.delete("/api/v1/bookings/789").mock(
            return_value=Response(202, json=response)
        )

        await client.cancel_booking(booking_id=789)

        request = mock_api.calls.last.request
        assert "X-Company-Id" not in request.headers


class TestListServicesByCategory:
    """Tests for list_services_by_category."""

    async def test_list_services_by_category_success(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test listing services grouped by category."""
        response = {
            "data": [
                {
                    "id": 1,
                    "name": "Cortes",
                    "services": [
                        {"id": 101, "name": "Corte Caballero"},
                        {"id": 102, "name": "Corte Dama"},
                    ],
                },
            ],
        }
        mock_api.get("/api/v1/categories/services").mock(
            return_value=Response(200, json=response)
        )

        result = await client.list_services_by_category(company_id=1238)

        assert "data" in result
        assert len(result["data"]) == 1
        assert result["data"][0]["name"] == "Cortes"

    async def test_list_services_by_category_with_active_filter(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test filtering services by active status."""
        response = {"data": []}
        mock_api.get("/api/v1/categories/services").mock(
            return_value=Response(200, json=response)
        )

        await client.list_services_by_category(company_id=1238, active=True)

        request = mock_api.calls.last.request
        assert "active=true" in str(request.url).lower()

    async def test_list_services_by_category_sends_company_id_as_query_param(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test that list_services_by_category sends company_id as query parameter."""
        response = {"data": []}
        mock_api.get("/api/v1/categories/services").mock(
            return_value=Response(200, json=response)
        )

        await client.list_services_by_category(company_id=9479)

        request = mock_api.calls.last.request
        assert "company_id=9479" in str(request.url)
        assert "X-Company-Id" not in request.headers


class TestLocations:
    """Tests for location operations."""

    async def test_list_locations_success(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test successful location listing."""
        response = {
            "data": [
                {"id": 1, "name": "Main Office", "address": "123 Main St"},
                {"id": 2, "name": "Branch Office", "address": "456 Oak Ave"},
            ]
        }
        mock_api.get("/api/v1/locations").mock(
            return_value=Response(200, json=response)
        )

        result = await client.list_locations(company_id=1238)

        assert "data" in result
        assert len(result["data"]) == 2
        assert result["data"][0]["name"] == "Main Office"

    async def test_list_locations_with_pagination(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test location listing with pagination parameters."""
        response = {"data": []}
        mock_api.get("/api/v1/locations").mock(
            return_value=Response(200, json=response)
        )

        await client.list_locations(company_id=1238, page=2, per_page=10)

        request = mock_api.calls.last.request
        assert "page=2" in str(request.url)
        assert "per_page=10" in str(request.url)

    async def test_list_locations_sends_company_id_as_query_param(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test that list_locations sends company_id as query parameter."""
        response = {"data": []}
        mock_api.get("/api/v1/locations").mock(
            return_value=Response(200, json=response)
        )

        await client.list_locations(company_id=9479)

        request = mock_api.calls.last.request
        assert "company_id=9479" in str(request.url)
        assert "X-Company-Id" not in request.headers

    async def test_get_location_success(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test successful location retrieval."""
        response = {
            "id": 123,
            "name": "Main Office",
            "address": "123 Main St",
            "company": {"id": 1238},
        }
        mock_api.get("/api/v1/locations/123").mock(
            return_value=Response(200, json=response)
        )

        result = await client.get_location(location_id=123)

        assert result["id"] == 123
        assert result["name"] == "Main Office"

    async def test_get_location_no_company_id_needed(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test that get_location does not require company_id."""
        response = {"id": 123, "name": "Main Office"}
        mock_api.get("/api/v1/locations/123").mock(
            return_value=Response(200, json=response)
        )

        await client.get_location(location_id=123)

        request = mock_api.calls.last.request
        assert "X-Company-Id" not in request.headers


class TestMemberships:
    """Tests for membership operations."""

    async def test_list_memberships_success(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test successful membership listing."""
        response = {
            "data": [
                {"id": 1, "name": "Basic Plan", "price": 9999},
                {"id": 2, "name": "Premium Plan", "price": 19999},
            ]
        }
        mock_api.get("/api/v1/memberships").mock(
            return_value=Response(200, json=response)
        )

        result = await client.list_memberships(company_id=1238, client_ids=[10, 20])

        assert "data" in result
        assert len(result["data"]) == 2
        assert result["data"][0]["name"] == "Basic Plan"

    async def test_list_memberships_with_pagination(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test membership listing with pagination parameters."""
        response = {"data": []}
        mock_api.get("/api/v1/memberships").mock(
            return_value=Response(200, json=response)
        )

        await client.list_memberships(company_id=1238, client_ids=[10], page=2, per_page=10)

        request = mock_api.calls.last.request
        assert "page=2" in str(request.url)
        assert "per_page=10" in str(request.url)

    async def test_list_memberships_sends_company_id_as_query_param(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test that list_memberships sends company_id as query parameter."""
        response = {"data": []}
        mock_api.get("/api/v1/memberships").mock(
            return_value=Response(200, json=response)
        )

        await client.list_memberships(company_id=9479, client_ids=[5])

        request = mock_api.calls.last.request
        assert "company_id=9479" in str(request.url)
        assert "X-Company-Id" not in request.headers

    async def test_get_membership_success(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test successful membership retrieval."""
        response = {
            "id": 123,
            "name": "Premium Plan",
            "price": 19999,
            "company_id": 1238,
        }
        mock_api.get("/api/v1/memberships/123").mock(
            return_value=Response(200, json=response)
        )

        result = await client.get_membership(membership_id=123)

        assert result["id"] == 123
        assert result["name"] == "Premium Plan"

    async def test_get_membership_with_date(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test membership retrieval with date parameter."""
        response = {"id": 123, "name": "Premium Plan", "price": 19999}
        mock_api.get("/api/v1/memberships/123").mock(
            return_value=Response(200, json=response)
        )

        await client.get_membership(membership_id=123, date="2024-01-15")

        request = mock_api.calls.last.request
        assert "date=2024-01-15" in str(request.url)

    async def test_get_membership_no_company_id_needed(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test that get_membership does not require company_id."""
        response = {"id": 123, "name": "Premium Plan"}
        mock_api.get("/api/v1/memberships/123").mock(
            return_value=Response(200, json=response)
        )

        await client.get_membership(membership_id=123)

        request = mock_api.calls.last.request
        assert "X-Company-Id" not in request.headers


class TestUsers:
    """Tests for user operations."""

    async def test_get_user_success(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test successful user retrieval."""
        response = {
            "id": 456,
            "email": "user@example.com",
            "first_name": "John",
            "last_name": "Doe",
        }
        mock_api.get("/api/v1/users/456").mock(
            return_value=Response(200, json=response)
        )

        result = await client.get_user(user_id=456, company_id=1238)

        assert result["id"] == 456
        assert result["email"] == "user@example.com"
        assert result["first_name"] == "John"
        assert result["last_name"] == "Doe"

    async def test_get_user_sends_company_id_as_query_param(
        self,
        client: Platform2StepClient,
        mock_api: respx.MockRouter,
    ):
        """Test that get_user sends company_id as query parameter."""
        response = {"id": 456, "email": "user@example.com"}
        mock_api.get("/api/v1/users/456").mock(
            return_value=Response(200, json=response)
        )

        await client.get_user(user_id=456, company_id=9479)

        request = mock_api.calls.last.request
        assert "company_id=9479" in str(request.url)
        assert "X-Company-Id" not in request.headers
