from __future__ import annotations

import httpx
import pytest

from terminaluse.core.force_multipart import FORCE_MULTIPART
from terminaluse.core.http_client import AsyncHttpClient, HttpClient


class _FakeSyncHttpxClient:
    def __init__(self) -> None:
        self.calls: list[dict] = []

    def request(self, **kwargs):
        self.calls.append(kwargs)
        status_code = 500 if len(self.calls) == 1 else 200
        return httpx.Response(status_code=status_code)


class _FakeAsyncHttpxClient:
    def __init__(self) -> None:
        self.calls: list[dict] = []

    async def request(self, **kwargs):
        self.calls.append(kwargs)
        status_code = 500 if len(self.calls) == 1 else 200
        return httpx.Response(status_code=status_code)


def test_sync_retry_preserves_data_and_force_multipart():
    fake_httpx = _FakeSyncHttpxClient()
    client = HttpClient(
        httpx_client=fake_httpx,  # type: ignore[arg-type]
        base_timeout=lambda: None,
        base_headers=lambda: {},
    )

    response = client.request(
        method="POST",
        base_url="https://api.example.com",
        path="/v1/test",
        data={"name": "demo", "drop": None},
        force_multipart=True,
    )

    assert response.status_code == 200
    assert len(fake_httpx.calls) == 2
    assert fake_httpx.calls[0]["files"] == FORCE_MULTIPART
    assert fake_httpx.calls[1]["files"] == FORCE_MULTIPART
    assert fake_httpx.calls[0]["data"] == {"name": "demo"}
    assert fake_httpx.calls[1]["data"] == {"name": "demo"}


@pytest.mark.asyncio
async def test_async_retry_preserves_data_and_force_multipart():
    fake_httpx = _FakeAsyncHttpxClient()
    client = AsyncHttpClient(
        httpx_client=fake_httpx,  # type: ignore[arg-type]
        base_timeout=lambda: None,
        base_headers=lambda: {},
    )

    response = await client.request(
        method="POST",
        base_url="https://api.example.com",
        path="/v1/test",
        data={"name": "demo", "drop": None},
        force_multipart=True,
    )

    assert response.status_code == 200
    assert len(fake_httpx.calls) == 2
    assert fake_httpx.calls[0]["files"] == FORCE_MULTIPART
    assert fake_httpx.calls[1]["files"] == FORCE_MULTIPART
    assert fake_httpx.calls[0]["data"] == {"name": "demo"}
    assert fake_httpx.calls[1]["data"] == {"name": "demo"}
