"""
Tests for Story 2.13: URL Ingestion Validation

Note: URL download functionality was enhanced in Story 2.16 with streaming.
These tests validate the validation logic still works correctly.
"""

import io
import tempfile
from pathlib import Path
from unittest.mock import patch, MagicMock, AsyncMock
from zipfile import ZipFile

import pytest
from fastapi.testclient import TestClient

from main import app
from routes.translate_routes import get_authenticated_user


def create_valid_excel() -> bytes:
    """Create a minimal valid .xlsx file (ZIP with office content)."""
    buf = io.BytesIO()
    with ZipFile(buf, "w") as zf:
        zf.writestr(
            "[Content_Types].xml",
            '<?xml version="1.0"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"></Types>',
        )
        zf.writestr(
            "_rels/.rels",
            '<?xml version="1.0"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"></Relationships>',
        )
        zf.writestr(
            "xl/workbook.xml",
            '<?xml version="1.0"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"></workbook>',
        )
    buf.seek(0)
    return buf.read()


@pytest.fixture()
def client(monkeypatch):
    """TestClient with rate limiting and quota reservation bypassed for URL validation tests."""
    from middleware.rate_limiting import RateLimitMiddleware

    async def _dispatch(self, request, call_next):
        return await call_next(request)

    monkeypatch.setattr(RateLimitMiddleware, "dispatch", _dispatch)
    monkeypatch.setattr("routes.translate_routes.reserve_translation_quota", lambda user_id: True)
    from main import app

    return TestClient(app)


class MockUser:
    def __init__(self):
        self.id = "user_abc123"
        self.plan = "pro"
        self.docs_translated_this_month = 0
        self.pages_translated_this_month = 0
        self.extra_credits = 0


async def mock_get_authenticated_user():
    return MockUser()


def create_mock_client_with_stream(mock_response):
    """Helper to create a mock AsyncClient with properly mocked stream method."""

    class MockStreamContextManager:
        async def __aenter__(self):
            return mock_response

        async def __aexit__(self, exc_type, exc_val, exc_tb):
            return None

    from unittest.mock import Mock

    mock_client = Mock()
    mock_client.stream.return_value = MockStreamContextManager()
    mock_client.__aenter__ = AsyncMock(return_value=mock_client)
    mock_client.__aexit__ = AsyncMock(return_value=None)

    return mock_client


@pytest.mark.asyncio
async def test_validate_file_url_invalid_format(client):
    """Test that invalid file format (.txt) returns INVALID_FORMAT error."""
    app.dependency_overrides[get_authenticated_user] = mock_get_authenticated_user
    try:
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.headers = {"content-disposition": "attachment; filename=test.txt"}

        mock_client = create_mock_client_with_stream(mock_response)

        with patch("httpx.AsyncClient", return_value=mock_client):
            response = client.post(
                "/api/v1/translate",
                data={"target_lang": "fr", "file_url": "https://example.com/test.txt"},
            )
            assert response.status_code == 400
            assert response.json()["error"] == "INVALID_FORMAT"
    finally:
        app.dependency_overrides.clear()


@pytest.mark.asyncio
async def test_validate_file_url_corrupted_magic_bytes(client):
    """Test that corrupted file (invalid magic bytes) returns CORRUPTED_FILE error."""
    app.dependency_overrides[get_authenticated_user] = mock_get_authenticated_user
    try:
        fake_content = b"not a zip file"

        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.headers = {
            "content-disposition": "attachment; filename=test.docx"
        }

        async def mock_aiter_bytes(chunk_size=65536):
            yield fake_content

        mock_response.aiter_bytes = mock_aiter_bytes

        mock_client = create_mock_client_with_stream(mock_response)

        with patch("httpx.AsyncClient", return_value=mock_client):
            response = client.post(
                "/api/v1/translate",
                data={"target_lang": "fr", "file_url": "https://example.com/test.docx"},
            )
            assert response.status_code == 400
            assert response.json()["error"] == "CORRUPTED_FILE"
            assert "corrompu" in response.json()["message"]
    finally:
        app.dependency_overrides.clear()
