"""
Unit Tests for Worksheet Editor API

Tests cover:
- Worksheet CRUD (create, read, list, delete)
- AI Image generation (mocked)
- PDF Export
- Health check

DSGVO Note: All tests run locally without external API calls.

BACKLOG: Feature not yet integrated into main.py
See: https://macmini:3002/infrastructure/tests
"""

import pytest
import sys

# Skip entire module if worksheet_editor_api is not available
pytest.importorskip("worksheet_editor_api", reason="worksheet_editor_api not yet integrated - Backlog item")

# Mark all tests in this module as expected failures (backlog item)
pytestmark = pytest.mark.xfail(
    reason="worksheet_editor_api not yet integrated into main.py - Backlog item",
    strict=False  # Don't fail if test unexpectedly passes
)
import json
import uuid
import io
import os
from datetime import datetime
from unittest.mock import AsyncMock, MagicMock, patch
from fastapi.testclient import TestClient

# Import the main app and worksheet-editor components
sys.path.insert(0, '..')
from main import app
from worksheet.editor_api import (
    worksheets_db,
    AIImageStyle,
    WorksheetStatus,
    WORKSHEET_STORAGE_DIR,
)


# =============================================
# FIXTURES
# =============================================

@pytest.fixture
def client():
    """Test client for FastAPI app."""
    return TestClient(app)


@pytest.fixture(autouse=True)
def clear_storage():
    """Clear in-memory storage before each test."""
    worksheets_db.clear()
    # Clean up test files
    if os.path.exists(WORKSHEET_STORAGE_DIR):
        for f in os.listdir(WORKSHEET_STORAGE_DIR):
            if f.startswith('test_') or f.startswith('ws_test_'):
                os.remove(os.path.join(WORKSHEET_STORAGE_DIR, f))
    yield
    worksheets_db.clear()


@pytest.fixture
def sample_worksheet_data():
    """Sample worksheet data."""
    return {
        "title": "Test Arbeitsblatt",
        "description": "Testbeschreibung",
        "pages": [
            {
                "id": "page_1",
                "index": 0,
                "canvasJSON": json.dumps({
                    "objects": [
                        {
                            "type": "text",
                            "text": "Überschrift",
                            "left": 100,
                            "top": 50,
                            "fontSize": 24
                        },
                        {
                            "type": "rect",
                            "left": 100,
                            "top": 100,
                            "width": 200,
                            "height": 100
                        }
                    ]
                })
            }
        ],
        "pageFormat": {
            "width": 210,
            "height": 297,
            "orientation": "portrait",
            "margins": {"top": 15, "right": 15, "bottom": 15, "left": 15}
        }
    }


@pytest.fixture
def sample_multipage_worksheet():
    """Sample worksheet with multiple pages."""
    return {
        "title": "Mehrseitiges Arbeitsblatt",
        "pages": [
            {"id": "page_1", "index": 0, "canvasJSON": "{}"},
            {"id": "page_2", "index": 1, "canvasJSON": "{}"},
            {"id": "page_3", "index": 2, "canvasJSON": "{}"},
        ]
    }


# =============================================
# WORKSHEET CRUD TESTS
# =============================================

class TestWorksheetCRUD:
    """Tests for Worksheet CRUD operations."""

    def test_create_worksheet(self, client, sample_worksheet_data):
        """Test creating a new worksheet."""
        response = client.post(
            "/api/v1/worksheet/save",
            json=sample_worksheet_data
        )

        assert response.status_code == 200
        data = response.json()

        assert "id" in data
        assert data["id"].startswith("ws_")
        assert data["title"] == sample_worksheet_data["title"]
        assert data["description"] == sample_worksheet_data["description"]
        assert len(data["pages"]) == 1
        assert "createdAt" in data
        assert "updatedAt" in data

    def test_update_worksheet(self, client, sample_worksheet_data):
        """Test updating an existing worksheet."""
        # First create
        create_response = client.post(
            "/api/v1/worksheet/save",
            json=sample_worksheet_data
        )
        worksheet_id = create_response.json()["id"]

        # Then update
        sample_worksheet_data["id"] = worksheet_id
        sample_worksheet_data["title"] = "Aktualisiertes Arbeitsblatt"

        update_response = client.post(
            "/api/v1/worksheet/save",
            json=sample_worksheet_data
        )

        assert update_response.status_code == 200
        data = update_response.json()
        assert data["id"] == worksheet_id
        assert data["title"] == "Aktualisiertes Arbeitsblatt"

    def test_get_worksheet(self, client, sample_worksheet_data):
        """Test retrieving a worksheet by ID."""
        # Create first
        create_response = client.post(
            "/api/v1/worksheet/save",
            json=sample_worksheet_data
        )
        worksheet_id = create_response.json()["id"]

        # Then get
        get_response = client.get(f"/api/v1/worksheet/{worksheet_id}")

        assert get_response.status_code == 200
        data = get_response.json()
        assert data["id"] == worksheet_id
        assert data["title"] == sample_worksheet_data["title"]

    def test_get_nonexistent_worksheet(self, client):
        """Test retrieving a non-existent worksheet."""
        response = client.get("/api/v1/worksheet/ws_nonexistent123")

        assert response.status_code == 404
        assert "not found" in response.json()["detail"].lower()

    def test_list_worksheets(self, client, sample_worksheet_data):
        """Test listing all worksheets."""
        # Create multiple worksheets
        for i in range(3):
            data = sample_worksheet_data.copy()
            data["title"] = f"Arbeitsblatt {i+1}"
            client.post("/api/v1/worksheet/save", json=data)

        # List all
        response = client.get("/api/v1/worksheet/list/all")

        assert response.status_code == 200
        data = response.json()
        assert "worksheets" in data
        assert "total" in data
        assert data["total"] >= 3

    def test_delete_worksheet(self, client, sample_worksheet_data):
        """Test deleting a worksheet."""
        # Create first
        create_response = client.post(
            "/api/v1/worksheet/save",
            json=sample_worksheet_data
        )
        worksheet_id = create_response.json()["id"]

        # Delete
        delete_response = client.delete(f"/api/v1/worksheet/{worksheet_id}")

        assert delete_response.status_code == 200
        assert delete_response.json()["status"] == "deleted"

        # Verify it's gone
        get_response = client.get(f"/api/v1/worksheet/{worksheet_id}")
        assert get_response.status_code == 404

    def test_delete_nonexistent_worksheet(self, client):
        """Test deleting a non-existent worksheet."""
        response = client.delete("/api/v1/worksheet/ws_nonexistent123")

        assert response.status_code == 404


# =============================================
# MULTIPAGE TESTS
# =============================================

class TestMultipageWorksheet:
    """Tests for multi-page worksheet functionality."""

    def test_create_multipage_worksheet(self, client, sample_multipage_worksheet):
        """Test creating a worksheet with multiple pages."""
        response = client.post(
            "/api/v1/worksheet/save",
            json=sample_multipage_worksheet
        )

        assert response.status_code == 200
        data = response.json()
        assert len(data["pages"]) == 3

    def test_page_indices(self, client, sample_multipage_worksheet):
        """Test that page indices are preserved."""
        response = client.post(
            "/api/v1/worksheet/save",
            json=sample_multipage_worksheet
        )

        data = response.json()
        for i, page in enumerate(data["pages"]):
            assert page["index"] == i


# =============================================
# AI IMAGE TESTS
# =============================================

class TestAIImageGeneration:
    """Tests for AI image generation."""

    def test_ai_image_with_valid_prompt(self, client):
        """Test AI image generation with valid prompt."""
        response = client.post(
            "/api/v1/worksheet/ai-image",
            json={
                "prompt": "A friendly cartoon dog reading a book",
                "style": "cartoon",
                "width": 256,
                "height": 256
            }
        )

        # Should return 200 (with placeholder) since Ollama may not be running
        assert response.status_code == 200
        data = response.json()
        assert "image_base64" in data
        assert data["image_base64"].startswith("data:image/png;base64,")
        assert "prompt_used" in data

    def test_ai_image_styles(self, client):
        """Test different AI image styles."""
        styles = ["realistic", "cartoon", "sketch", "clipart", "educational"]

        for style in styles:
            response = client.post(
                "/api/v1/worksheet/ai-image",
                json={
                    "prompt": "Test image",
                    "style": style,
                    "width": 256,
                    "height": 256
                }
            )

            assert response.status_code == 200
            data = response.json()
            assert style in data["prompt_used"].lower() or "test image" in data["prompt_used"].lower()

    def test_ai_image_empty_prompt(self, client):
        """Test AI image generation with empty prompt."""
        response = client.post(
            "/api/v1/worksheet/ai-image",
            json={
                "prompt": "",
                "style": "educational",
                "width": 256,
                "height": 256
            }
        )

        assert response.status_code == 422  # Validation error

    def test_ai_image_invalid_dimensions(self, client):
        """Test AI image generation with invalid dimensions."""
        response = client.post(
            "/api/v1/worksheet/ai-image",
            json={
                "prompt": "Test",
                "style": "educational",
                "width": 50,  # Too small
                "height": 256
            }
        )

        assert response.status_code == 422  # Validation error


# =============================================
# CANVAS JSON TESTS
# =============================================

class TestCanvasJSON:
    """Tests for canvas JSON handling."""

    def test_save_and_load_canvas_json(self, client):
        """Test that canvas JSON is preserved correctly."""
        canvas_data = {
            "objects": [
                {"type": "text", "text": "Hello", "left": 10, "top": 10},
                {"type": "rect", "left": 50, "top": 50, "width": 100, "height": 50}
            ],
            "background": "#ffffff"
        }

        worksheet_data = {
            "title": "Canvas Test",
            "pages": [{
                "id": "page_1",
                "index": 0,
                "canvasJSON": json.dumps(canvas_data)
            }]
        }

        # Save
        create_response = client.post(
            "/api/v1/worksheet/save",
            json=worksheet_data
        )
        worksheet_id = create_response.json()["id"]

        # Load
        get_response = client.get(f"/api/v1/worksheet/{worksheet_id}")
        loaded_data = get_response.json()

        # Compare
        loaded_canvas = json.loads(loaded_data["pages"][0]["canvasJSON"])
        assert loaded_canvas["objects"] == canvas_data["objects"]

    def test_empty_canvas_json(self, client):
        """Test worksheet with empty canvas JSON."""
        worksheet_data = {
            "title": "Empty Canvas",
            "pages": [{
                "id": "page_1",
                "index": 0,
                "canvasJSON": "{}"
            }]
        }

        response = client.post(
            "/api/v1/worksheet/save",
            json=worksheet_data
        )

        assert response.status_code == 200


# =============================================
# PAGE FORMAT TESTS
# =============================================

class TestPageFormat:
    """Tests for page format handling."""

    def test_default_page_format(self, client):
        """Test that default page format is applied."""
        worksheet_data = {
            "title": "Default Format",
            "pages": [{"id": "p1", "index": 0, "canvasJSON": "{}"}]
        }

        response = client.post(
            "/api/v1/worksheet/save",
            json=worksheet_data
        )

        data = response.json()
        assert data["pageFormat"]["width"] == 210
        assert data["pageFormat"]["height"] == 297
        assert data["pageFormat"]["orientation"] == "portrait"

    def test_custom_page_format(self, client):
        """Test custom page format."""
        worksheet_data = {
            "title": "Custom Format",
            "pages": [{"id": "p1", "index": 0, "canvasJSON": "{}"}],
            "pageFormat": {
                "width": 297,
                "height": 210,
                "orientation": "landscape",
                "margins": {"top": 20, "right": 20, "bottom": 20, "left": 20}
            }
        }

        response = client.post(
            "/api/v1/worksheet/save",
            json=worksheet_data
        )

        data = response.json()
        assert data["pageFormat"]["width"] == 297
        assert data["pageFormat"]["height"] == 210
        assert data["pageFormat"]["orientation"] == "landscape"


# =============================================
# HEALTH CHECK TESTS
# =============================================

class TestHealthCheck:
    """Tests for health check endpoint."""

    def test_health_check(self, client):
        """Test health check endpoint."""
        response = client.get("/api/v1/worksheet/health/check")

        assert response.status_code == 200
        data = response.json()
        assert "status" in data
        assert data["status"] == "healthy"
        assert "storage" in data
        assert "reportlab" in data


# =============================================
# PDF EXPORT TESTS
# =============================================

class TestPDFExport:
    """Tests for PDF export functionality."""

    def test_export_pdf(self, client, sample_worksheet_data):
        """Test PDF export of a worksheet."""
        # Create worksheet
        create_response = client.post(
            "/api/v1/worksheet/save",
            json=sample_worksheet_data
        )
        worksheet_id = create_response.json()["id"]

        # Export
        export_response = client.post(
            f"/api/v1/worksheet/{worksheet_id}/export-pdf"
        )

        # Check response (may be 501 if reportlab not installed)
        assert export_response.status_code in [200, 501]

        if export_response.status_code == 200:
            assert export_response.headers["content-type"] == "application/pdf"
            assert "attachment" in export_response.headers.get("content-disposition", "")

    def test_export_nonexistent_worksheet_pdf(self, client):
        """Test PDF export of non-existent worksheet."""
        response = client.post("/api/v1/worksheet/ws_nonexistent/export-pdf")

        assert response.status_code in [404, 501]


# =============================================
# ERROR HANDLING TESTS
# =============================================

class TestErrorHandling:
    """Tests for error handling."""

    def test_invalid_json(self, client):
        """Test handling of invalid JSON."""
        response = client.post(
            "/api/v1/worksheet/save",
            content="not valid json",
            headers={"Content-Type": "application/json"}
        )

        assert response.status_code == 422

    def test_missing_required_fields(self, client):
        """Test handling of missing required fields."""
        response = client.post(
            "/api/v1/worksheet/save",
            json={"pages": []}  # Missing title
        )

        assert response.status_code == 422

    def test_empty_pages_array(self, client):
        """Test worksheet with empty pages array."""
        response = client.post(
            "/api/v1/worksheet/save",
            json={
                "title": "No Pages",
                "pages": []
            }
        )

        # Should still work - empty worksheets are allowed
        assert response.status_code == 200
