"""
Worksheet Editor API - Backend Endpoints for Visual Worksheet Editor

Provides endpoints for:
- AI Image generation via Ollama/Stable Diffusion
- Worksheet Save/Load
- PDF Export

Split modules:
- worksheet_editor_models: Enums, Pydantic models, configuration
- worksheet_editor_ai: AI image generation and AI worksheet modification
- worksheet_editor_reconstruct: Document reconstruction from vocab sessions
"""

import os
import io
import json
import logging
from datetime import datetime, timezone
import uuid

from fastapi import APIRouter, HTTPException
from fastapi.responses import StreamingResponse
import httpx

# Re-export everything from sub-modules for backward compatibility
from .editor_models import (  # noqa: F401
    AIImageStyle,
    WorksheetStatus,
    AIImageRequest,
    AIImageResponse,
    PageData,
    PageFormat,
    WorksheetSaveRequest,
    WorksheetResponse,
    AIModifyRequest,
    AIModifyResponse,
    ReconstructRequest,
    ReconstructResponse,
    worksheets_db,
    OLLAMA_URL,
    SD_MODEL,
    WORKSHEET_STORAGE_DIR,
    STYLE_PROMPTS,
    REPORTLAB_AVAILABLE,
)

from .editor_ai import (  # noqa: F401
    generate_ai_image_logic,
    _generate_placeholder_image,
    modify_worksheet_with_ai_logic,
    _handle_simple_modification,
)

from .editor_reconstruct import (  # noqa: F401
    reconstruct_document_logic,
    _detect_image_regions,
)

logger = logging.getLogger(__name__)

# =============================================
# ROUTER
# =============================================

router = APIRouter(prefix="/api/v1/worksheet", tags=["Worksheet Editor"])

# =============================================
# AI IMAGE GENERATION
# =============================================

@router.post("/ai-image", response_model=AIImageResponse)
async def generate_ai_image(request: AIImageRequest):
    """
    Generate an AI image using Ollama with a text-to-image model.

    Supported models:
    - stable-diffusion (via Ollama)
    - sd3.5-medium
    - llava (for image understanding, not generation)

    Falls back to a placeholder if Ollama is not available.
    """
    return await generate_ai_image_logic(request)


# =============================================
# WORKSHEET SAVE/LOAD
# =============================================

@router.post("/save", response_model=WorksheetResponse)
async def save_worksheet(request: WorksheetSaveRequest):
    """
    Save a worksheet document.

    - If id is provided, updates existing worksheet
    - If id is not provided, creates new worksheet
    """
    try:
        now = datetime.now(timezone.utc).isoformat()

        worksheet_id = request.id or f"ws_{uuid.uuid4().hex[:12]}"

        worksheet = {
            "id": worksheet_id,
            "title": request.title,
            "description": request.description,
            "pages": [p.dict() for p in request.pages],
            "pageFormat": (request.pageFormat or PageFormat()).dict(),
            "createdAt": worksheets_db.get(worksheet_id, {}).get("createdAt", now),
            "updatedAt": now
        }

        worksheets_db[worksheet_id] = worksheet

        filepath = os.path.join(WORKSHEET_STORAGE_DIR, f"{worksheet_id}.json")
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(worksheet, f, ensure_ascii=False, indent=2)

        logger.info(f"Saved worksheet: {worksheet_id}")

        return WorksheetResponse(**worksheet)

    except Exception as e:
        logger.error(f"Failed to save worksheet: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to save: {str(e)}")


@router.get("/{worksheet_id}", response_model=WorksheetResponse)
async def get_worksheet(worksheet_id: str):
    """Load a worksheet document by ID."""
    try:
        if worksheet_id in worksheets_db:
            return WorksheetResponse(**worksheets_db[worksheet_id])

        filepath = os.path.join(WORKSHEET_STORAGE_DIR, f"{worksheet_id}.json")
        if os.path.exists(filepath):
            with open(filepath, 'r', encoding='utf-8') as f:
                worksheet = json.load(f)
                worksheets_db[worksheet_id] = worksheet
                return WorksheetResponse(**worksheet)

        raise HTTPException(status_code=404, detail="Worksheet not found")

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to load worksheet {worksheet_id}: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to load: {str(e)}")


@router.get("/list/all")
async def list_worksheets():
    """List all available worksheets."""
    try:
        worksheets = []

        for filename in os.listdir(WORKSHEET_STORAGE_DIR):
            if filename.endswith('.json'):
                filepath = os.path.join(WORKSHEET_STORAGE_DIR, filename)
                try:
                    with open(filepath, 'r', encoding='utf-8') as f:
                        worksheet = json.load(f)
                        worksheets.append({
                            "id": worksheet.get("id"),
                            "title": worksheet.get("title"),
                            "description": worksheet.get("description"),
                            "pageCount": len(worksheet.get("pages", [])),
                            "updatedAt": worksheet.get("updatedAt"),
                            "createdAt": worksheet.get("createdAt")
                        })
                except Exception as e:
                    logger.warning(f"Failed to load {filename}: {e}")

        worksheets.sort(key=lambda x: x.get("updatedAt", ""), reverse=True)

        return {"worksheets": worksheets, "total": len(worksheets)}

    except Exception as e:
        logger.error(f"Failed to list worksheets: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/{worksheet_id}")
async def delete_worksheet(worksheet_id: str):
    """Delete a worksheet document."""
    try:
        if worksheet_id in worksheets_db:
            del worksheets_db[worksheet_id]

        filepath = os.path.join(WORKSHEET_STORAGE_DIR, f"{worksheet_id}.json")
        if os.path.exists(filepath):
            os.remove(filepath)
            logger.info(f"Deleted worksheet: {worksheet_id}")
            return {"status": "deleted", "id": worksheet_id}

        raise HTTPException(status_code=404, detail="Worksheet not found")

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to delete worksheet {worksheet_id}: {e}")
        raise HTTPException(status_code=500, detail=str(e))


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

@router.post("/{worksheet_id}/export-pdf")
async def export_worksheet_pdf(worksheet_id: str):
    """
    Export worksheet as PDF.

    Note: This creates a basic PDF. For full canvas rendering,
    the frontend should use pdf-lib with canvas.toDataURL().
    """
    if not REPORTLAB_AVAILABLE:
        raise HTTPException(status_code=501, detail="PDF export not available (reportlab not installed)")

    try:
        from reportlab.lib.pagesizes import A4
        from reportlab.pdfgen import canvas

        worksheet = worksheets_db.get(worksheet_id)
        if not worksheet:
            filepath = os.path.join(WORKSHEET_STORAGE_DIR, f"{worksheet_id}.json")
            if os.path.exists(filepath):
                with open(filepath, 'r', encoding='utf-8') as f:
                    worksheet = json.load(f)
            else:
                raise HTTPException(status_code=404, detail="Worksheet not found")

        buffer = io.BytesIO()
        c = canvas.Canvas(buffer, pagesize=A4)

        page_width, page_height = A4

        for page_data in worksheet.get("pages", []):
            if page_data.get("index", 0) == 0:
                c.setFont("Helvetica-Bold", 18)
                c.drawString(50, page_height - 50, worksheet.get("title", "Arbeitsblatt"))
                c.setFont("Helvetica", 10)
                c.drawString(50, page_height - 70, f"Erstellt: {worksheet.get('createdAt', '')[:10]}")

            canvas_json_str = page_data.get("canvasJSON", "{}")
            if canvas_json_str:
                try:
                    canvas_data = json.loads(canvas_json_str)
                    objects = canvas_data.get("objects", [])

                    for obj in objects:
                        obj_type = obj.get("type", "")

                        if obj_type in ["text", "i-text", "textbox"]:
                            text = obj.get("text", "")
                            left = obj.get("left", 50)
                            top = obj.get("top", 100)
                            font_size = obj.get("fontSize", 12)

                            pdf_x = left * 0.75
                            pdf_y = page_height - (top * 0.75)

                            c.setFont("Helvetica", min(font_size, 24))
                            c.drawString(pdf_x, pdf_y, text[:100])

                        elif obj_type == "rect":
                            left = obj.get("left", 0) * 0.75
                            top = obj.get("top", 0) * 0.75
                            width = obj.get("width", 50) * 0.75
                            height = obj.get("height", 30) * 0.75
                            c.rect(left, page_height - top - height, width, height)

                        elif obj_type == "circle":
                            left = obj.get("left", 0) * 0.75
                            top = obj.get("top", 0) * 0.75
                            radius = obj.get("radius", 25) * 0.75
                            c.circle(left + radius, page_height - top - radius, radius)

                except json.JSONDecodeError:
                    pass

            c.showPage()

        c.save()
        buffer.seek(0)

        filename = f"{worksheet.get('title', 'worksheet').replace(' ', '_')}.pdf"

        return StreamingResponse(
            buffer,
            media_type="application/pdf",
            headers={"Content-Disposition": f"attachment; filename={filename}"}
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"PDF export failed: {e}")
        raise HTTPException(status_code=500, detail=str(e))


# =============================================
# AI WORKSHEET MODIFICATION
# =============================================

@router.post("/ai-modify", response_model=AIModifyResponse)
async def modify_worksheet_with_ai(request: AIModifyRequest):
    """
    Modify a worksheet using AI based on natural language prompt.

    Uses Ollama with qwen2.5vl:32b to understand the canvas state
    and generate modifications based on the user's request.
    """
    return await modify_worksheet_with_ai_logic(request)


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

@router.get("/health/check")
async def health_check():
    """Check worksheet editor API health and dependencies."""
    status = {
        "status": "healthy",
        "ollama": False,
        "storage": os.path.exists(WORKSHEET_STORAGE_DIR),
        "reportlab": REPORTLAB_AVAILABLE,
        "worksheets_count": len(worksheets_db)
    }

    try:
        async with httpx.AsyncClient(timeout=5.0) as client:
            response = await client.get(f"{OLLAMA_URL}/api/tags")
            status["ollama"] = response.status_code == 200
    except Exception:
        pass

    return status


# =============================================
# DOCUMENT RECONSTRUCTION FROM VOCAB SESSION
# =============================================

@router.post("/reconstruct-from-session", response_model=ReconstructResponse)
async def reconstruct_document_from_session(request: ReconstructRequest):
    """
    Reconstruct a document from a vocab session into Fabric.js canvas format.

    Returns canvas JSON ready to load into the worksheet editor.
    """
    try:
        return await reconstruct_document_logic(request)
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Document reconstruction failed: {e}")
        import traceback
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/sessions/available")
async def get_available_sessions():
    """Get list of available vocab sessions that can be reconstructed."""
    try:
        from vocab.worksheet.api import _sessions

        available = []
        for session_id, session in _sessions.items():
            if session.get("pdf_data"):
                available.append({
                    "id": session_id,
                    "name": session.get("name", "Unnamed"),
                    "description": session.get("description"),
                    "vocabulary_count": len(session.get("vocabulary", [])),
                    "page_count": session.get("pdf_page_count", 1),
                    "status": session.get("status", "unknown"),
                    "created_at": session.get("created_at", "").isoformat() if session.get("created_at") else None
                })

        return {"sessions": available, "total": len(available)}

    except Exception as e:
        logger.error(f"Failed to list sessions: {e}")
        raise HTTPException(status_code=500, detail=str(e))
