"""Tests for /api/v1/diagrams/render.

- Unit: mmdc yoksa 503, geçersiz mermaid syntax → 400 (mock ile)
- Integration: mmdc kurulu ise gerçek PNG üretimi
"""

from __future__ import annotations

from unittest.mock import AsyncMock, patch

import pytest
from httpx import ASGITransport, AsyncClient

from app.main import app
from app.services.mermaid.renderer import (
    MermaidNotInstalledError,
    MermaidRenderError,
    mmdc_available,
)

SIMPLE_MERMAID = """
flowchart TD
    A[İstemci] --> B[Ağ Geçidi]
    B --> C[ML-DSA Modülü]
    C --> D[Şifreli Tünel]
"""


@pytest.mark.asyncio
async def test_render_returns_503_when_mmdc_missing() -> None:
    with patch(
        "app.api.diagrams.render_mermaid_to_png",
        side_effect=MermaidNotInstalledError("mmdc bulunamadı"),
    ):
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            response = await client.post("/api/v1/diagrams/render", json={"source": SIMPLE_MERMAID})
    assert response.status_code == 503
    assert "mmdc" in response.json()["detail"].lower()


@pytest.mark.asyncio
async def test_render_returns_400_on_invalid_mermaid() -> None:
    with patch(
        "app.api.diagrams.render_mermaid_to_png",
        side_effect=MermaidRenderError("mmdc exit 1: syntax error"),
    ):
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            response = await client.post(
                "/api/v1/diagrams/render", json={"source": "not valid mermaid"}
            )
    assert response.status_code == 400
    assert "syntax" in response.json()["detail"].lower()


@pytest.mark.asyncio
async def test_render_returns_png_bytes_with_mock() -> None:
    """Mock ile: endpoint returned bytes'ı application/png olarak döner mi."""
    # PNG magic bytes: 89 50 4E 47 0D 0A 1A 0A
    fake_png = b"\x89PNG\r\n\x1a\n" + b"\x00" * 100

    with patch(
        "app.api.diagrams.render_mermaid_to_png",
        new=AsyncMock(return_value=fake_png),
    ):
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            response = await client.post(
                "/api/v1/diagrams/render",
                json={"source": SIMPLE_MERMAID, "scale": 3, "width": 1200},
            )

    assert response.status_code == 200
    assert response.headers["content-type"] == "image/png"
    assert response.content.startswith(b"\x89PNG")


@pytest.mark.asyncio
async def test_render_validates_source_length() -> None:
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        response = await client.post("/api/v1/diagrams/render", json={"source": "x"})
    assert response.status_code == 422


# ------------------- Integration test (requires real mmdc) -------------------


@pytest.mark.asyncio
@pytest.mark.skipif(not mmdc_available(), reason="mmdc/Node not installed")
async def test_real_mermaid_render_produces_png() -> None:
    """mmdc kurulu ise: gerçek render yapılır, PNG magic bytes kontrolü."""
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test", timeout=60.0) as client:
        response = await client.post(
            "/api/v1/diagrams/render",
            json={"source": SIMPLE_MERMAID, "scale": 2, "width": 800},
        )

    assert response.status_code == 200, response.text
    assert response.headers["content-type"] == "image/png"
    assert response.content.startswith(b"\x89PNG\r\n\x1a\n"), "PNG magic bytes"
    # Gerçek PNG genellikle >1 KB
    assert len(response.content) > 1000
