"""Tests for /train and /segtrain endpoint authentication."""

import io
import zipfile
from unittest.mock import AsyncMock, patch

import pytest
from httpx import ASGITransport, AsyncClient

from main import app


def _minimal_zip() -> bytes:
    """Return a ZIP with one .xml file so endpoint validation passes."""
    buf = io.BytesIO()
    with zipfile.ZipFile(buf, "w") as zf:
        zf.writestr("page_01.xml", "<PcGts/>")
    return buf.getvalue()


# ─── Missing TRAINING_TOKEN → fail closed ─────────────────────────────────────


@pytest.mark.asyncio
async def test_train_returns_503_when_training_token_not_configured():
    """POST /train must return 503 when TRAINING_TOKEN env var is empty.

    An empty token means the service was started without training configured.
    Allowing requests through would grant unauthenticated access to the
    training endpoint, contradicting the principle of failing closed.
    """
    with patch("main.TRAINING_TOKEN", ""), \
         patch("main._models_ready", True):
        async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
            response = await client.post(
                "/train",
                files={"file": ("training.zip", _minimal_zip(), "application/zip")},
            )

    assert response.status_code == 503


@pytest.mark.asyncio
async def test_segtrain_returns_503_when_training_token_not_configured():
    """POST /segtrain must return 503 when TRAINING_TOKEN env var is empty."""
    with patch("main.TRAINING_TOKEN", ""), \
         patch("main._models_ready", True):
        async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
            response = await client.post(
                "/segtrain",
                files={"file": ("training.zip", _minimal_zip(), "application/zip")},
            )

    assert response.status_code == 503


@pytest.mark.asyncio
async def test_train_returns_403_when_token_wrong():
    """POST /train must return 403 when TRAINING_TOKEN is set but header is wrong."""
    with patch("main.TRAINING_TOKEN", "secret-token"), \
         patch("main._models_ready", True):
        async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
            response = await client.post(
                "/train",
                files={"file": ("training.zip", _minimal_zip(), "application/zip")},
                headers={"X-Training-Token": "wrong-token"},
            )

    assert response.status_code == 403


# ─── /train-sender authentication ─────────────────────────────────────────────


@pytest.mark.asyncio
async def test_train_sender_returns_503_when_training_token_not_configured():
    """POST /train-sender must return 503 when TRAINING_TOKEN env var is empty.

    An empty token means the service was started without training configured.
    Allowing requests through would grant unauthenticated access to the
    training endpoint, contradicting the principle of failing closed.
    """
    with patch("main.TRAINING_TOKEN", ""), \
         patch("main._models_ready", True):
        async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
            response = await client.post(
                "/train-sender",
                data={"output_model_path": "/app/models/sender_test.mlmodel"},
                files={"file": ("training.zip", _minimal_zip(), "application/zip")},
            )

    assert response.status_code == 503


@pytest.mark.asyncio
async def test_train_sender_returns_403_when_token_wrong():
    """POST /train-sender must return 403 when TRAINING_TOKEN is set but header is wrong."""
    with patch("main.TRAINING_TOKEN", "secret-token"), \
         patch("main._models_ready", True):
        async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
            response = await client.post(
                "/train-sender",
                data={"output_model_path": "/app/models/sender_test.mlmodel"},
                files={"file": ("training.zip", _minimal_zip(), "application/zip")},
                headers={"X-Training-Token": "wrong-token"},
            )

    assert response.status_code == 403
