"""Tests for pdf_client module."""

from __future__ import annotations

from unittest.mock import AsyncMock, MagicMock, patch

import httpx
import pytest

from complyform.core.errors import (
    GotenbergPayloadTooLargeError,
    GotenbergRenderError,
    GotenbergTimeoutError,
)
from complyform.reporting.pdf_client import request_pdf

_PATCH_TARGET = "complyform.reporting.pdf_client.httpx.AsyncClient"


def _mock_client(
    response: MagicMock | None = None,
    side_effect: Exception | None = None,
) -> AsyncMock:
    """Build a mock httpx.AsyncClient context manager."""
    client = AsyncMock()
    if side_effect:
        client.post = AsyncMock(side_effect=side_effect)
    else:
        client.post = AsyncMock(return_value=response)
    client.__aenter__ = AsyncMock(return_value=client)
    client.__aexit__ = AsyncMock(return_value=False)
    return client


@pytest.mark.asyncio
async def test_request_pdf_success() -> None:
    """Mock httpx — returns PDF bytes on 200."""
    resp = MagicMock()
    resp.status_code = 200
    resp.content = b"%PDF-1.4 fake pdf"
    resp.text = ""

    client = _mock_client(response=resp)
    with patch(_PATCH_TARGET, return_value=client):
        result = await request_pdf(
            api_base_url="https://api.example.com",
            api_key="test-key-123",
            html_content="<html><body>Hello</body></html>",
        )

    assert result == b"%PDF-1.4 fake pdf"


@pytest.mark.asyncio
async def test_request_pdf_payload_too_large() -> None:
    """>10MB HTML raises GotenbergPayloadTooLargeError."""
    huge_html = "x" * (11 * 1024 * 1024)

    with pytest.raises(GotenbergPayloadTooLargeError):
        await request_pdf(
            api_base_url="https://api.example.com",
            api_key="test-key",
            html_content=huge_html,
        )


@pytest.mark.asyncio
async def test_request_pdf_timeout() -> None:
    """Mock timeout raises GotenbergTimeoutError."""
    client = _mock_client(
        side_effect=httpx.TimeoutException("timed out"),
    )

    with (
        patch(_PATCH_TARGET, return_value=client),
        pytest.raises(GotenbergTimeoutError),
    ):
        await request_pdf(
            api_base_url="https://api.example.com",
            api_key="test-key",
            html_content="<html></html>",
        )


@pytest.mark.asyncio
async def test_request_pdf_server_error() -> None:
    """500 raises GotenbergRenderError."""
    resp = MagicMock()
    resp.status_code = 500
    resp.text = "Internal Server Error"

    client = _mock_client(response=resp)

    with (
        patch(_PATCH_TARGET, return_value=client),
        pytest.raises(GotenbergRenderError),
    ):
        await request_pdf(
            api_base_url="https://api.example.com",
            api_key="test-key",
            html_content="<html></html>",
        )


@pytest.mark.asyncio
async def test_request_pdf_with_brand() -> None:
    """Brand dict + logo_base64 included in request payload."""
    resp = MagicMock()
    resp.status_code = 200
    resp.content = b"%PDF-1.4"
    resp.text = ""

    client = _mock_client(response=resp)

    brand = {
        "company_name": "Acme",
        "primary_color": "#ff0000",
    }
    logo = "iVBORw0KGgoAAAANS..."

    with patch(_PATCH_TARGET, return_value=client):
        await request_pdf(
            api_base_url="https://api.example.com",
            api_key="test-key",
            html_content="<html></html>",
            brand=brand,
            logo_base64=logo,
        )

    # Verify the POST payload included brand and logo
    call_kwargs = client.post.call_args
    payload = call_kwargs.kwargs.get("json") or call_kwargs[1].get("json")
    assert payload["brand"] == brand
    assert payload["logo_base64"] == logo


@pytest.mark.asyncio
async def test_request_pdf_auth_header() -> None:
    """Verifies Authorization: Bearer header is set."""
    resp = MagicMock()
    resp.status_code = 200
    resp.content = b"%PDF"
    resp.text = ""

    client = _mock_client(response=resp)

    with patch(_PATCH_TARGET, return_value=client):
        await request_pdf(
            api_base_url="https://api.example.com",
            api_key="my-secret-key",
            html_content="<html></html>",
        )

    call_kwargs = client.post.call_args
    headers = call_kwargs.kwargs.get("headers") or call_kwargs[1].get("headers")
    assert headers["Authorization"] == "Bearer my-secret-key"
