import asyncio

import pytest
from fastapi import HTTPException

from modules.upload_validation import MAX_UPLOAD_BYTES, read_pdf_upload_bytes, read_upload_bytes


class FakeUpload:
    def __init__(self, data: bytes, content_type: str, filename: str = "file.bin"):
        self._data = data
        self._pos = 0
        self.content_type = content_type
        self.filename = filename

    async def read(self, size: int = -1) -> bytes:
        if self._pos >= len(self._data):
            return b""
        if size is None or size < 0:
            size = len(self._data) - self._pos
        chunk = self._data[self._pos : self._pos + size]
        self._pos += len(chunk)
        return chunk


def run(coro):
    return asyncio.run(coro)


def test_valid_pdf_upload_passes_and_returns_mime():
    data, mime = run(read_upload_bytes(FakeUpload(b"%PDF-1.7\n", "application/pdf")))
    assert data.startswith(b"%PDF-")
    assert mime == "application/pdf"


def test_disallowed_mime_rejected_with_415():
    with pytest.raises(HTTPException) as exc:
        run(read_upload_bytes(FakeUpload(b"print(1)", "application/x-python")))
    assert exc.value.status_code == 415
    assert "Unsupported upload type" in exc.value.detail


def test_oversize_upload_rejected_with_413():
    with pytest.raises(HTTPException) as exc:
        run(read_upload_bytes(FakeUpload(b"x" * (MAX_UPLOAD_BYTES + 1), "text/plain")))
    assert exc.value.status_code == 413
    assert "exceeds max size" in exc.value.detail


def test_pdf_helper_rejects_spoofed_pdf_mime():
    with pytest.raises(HTTPException) as exc:
        run(read_pdf_upload_bytes(FakeUpload(b"not a pdf", "application/pdf")))
    assert exc.value.status_code == 415
    assert "not a valid PDF" in exc.value.detail
