"""Document creation MCP tools for TokenMoulds.

Provides tools for creating styled documents in all supported formats.
All documents are based on TokenMoulds-generated templates - either brand-specific
or the generic TokenMoulds default template (full quality, non-branded).

Supported formats:
- Word (.docx) from .dotx template
- PowerPoint (.pptx) from .potx template
- Excel (.xlsx) from .xltx template
- Writer (.odt) from .ott template
- Impress (.odp) from .otp template
- Google Docs (.docx) optimized for Google Drive

NO minimal Office defaults - every document has full TokenMoulds quality.
"""

from __future__ import annotations

from datetime import datetime
from typing import TYPE_CHECKING, Any, Dict

from tokenmoulds.mcp.tools.document_pipeline.content_injection import (
    _inject_excel_content,
    _inject_impress_content,
    _inject_powerpoint_content,
    _inject_word_content,
    _inject_writer_content,
    _parse_markdown_to_blocks,
)
from tokenmoulds.mcp.tools.document_pipeline.template_acquisition import (
    GENERIC_BRAND_NAME,
    _get_excel_template,
    _get_impress_template,
    _get_powerpoint_template,
    _get_style_context,
    _get_word_template,
    _get_writer_template,
)
from tokenmoulds.mcp.validation import validate_template

if TYPE_CHECKING:
    from tokenmoulds.mcp.server import TokenMouldsServer

# ============================================================================
# JSON Schemas for MCP Tools
# ============================================================================

# Content block schema (shared across document types)
CONTENT_BLOCK_SCHEMA = {
    "type": "object",
    "properties": {
        "type": {
            "type": "string",
            "enum": [
                "title",
                "heading1",
                "heading2",
                "heading3",
                "heading4",
                "paragraph",
                "bullet_list",
                "numbered_list",
                "table",
                "quote",
                "code_block",
                "image",
                "page_break",
            ],
            "description": "Content block type",
        },
        "text": {
            "type": "string",
            "description": "Text content (for headings, paragraphs, quotes, code)",
        },
        "items": {
            "type": "array",
            "items": {"type": "string"},
            "description": "List items (for bullet_list, numbered_list)",
        },
        "rows": {
            "type": "array",
            "items": {
                "type": "array",
                "items": {"type": "string"},
            },
            "description": "Table rows including header row (for table)",
        },
        "level": {
            "type": "integer",
            "minimum": 0,
            "maximum": 8,
            "description": "Nesting level for lists (default 0)",
        },
        "language": {
            "type": "string",
            "description": "Programming language for code blocks",
        },
        "src": {
            "type": "string",
            "description": "Image source path or URL",
        },
        "alt": {
            "type": "string",
            "description": "Image alt text for accessibility",
        },
    },
    "required": ["type"],
}

CREATE_WORD_DOCUMENT_SCHEMA: Dict[str, Any] = {
    "type": "object",
    "properties": {
        "title": {
            "type": "string",
            "description": "Document title (used in metadata and optionally as first heading)",
        },
        "content": {
            "oneOf": [
                {
                    "type": "string",
                    "description": "Markdown content (# headings, - bullets, 1. numbered, ``` code, > quotes)",
                },
                {
                    "type": "array",
                    "description": "Structured content blocks",
                    "items": CONTENT_BLOCK_SCHEMA,
                },
            ],
            "description": "Document content as markdown string or structured blocks",
        },
        "brand_name": {
            "type": "string",
            "description": "Brand identifier (uses generic TokenMoulds template if not specified)",
        },
        "filename": {
            "type": "string",
            "description": "Output filename without extension (auto-generated if not specified)",
        },
        "add_title_page": {
            "type": "boolean",
            "default": False,
            "description": "Add a title page before content",
        },
        "include_toc": {
            "type": "boolean",
            "default": False,
            "description": "Include table of contents",
        },
        "metadata": {
            "type": "object",
            "properties": {
                "author": {"type": "string"},
                "subject": {"type": "string"},
                "keywords": {"type": "array", "items": {"type": "string"}},
                "category": {"type": "string"},
            },
            "description": "Document metadata",
        },
    },
    "required": ["title", "content"],
}

CREATE_POWERPOINT_DOCUMENT_SCHEMA: Dict[str, Any] = {
    "type": "object",
    "properties": {
        "title": {
            "type": "string",
            "description": "Presentation title",
        },
        "slides": {
            "type": "array",
            "description": "Slide content",
            "items": {
                "type": "object",
                "properties": {
                    "layout": {
                        "type": "string",
                        "enum": [
                            "title",
                            "title_content",
                            "section",
                            "two_column",
                            "blank",
                        ],
                        "description": "Slide layout type",
                    },
                    "title": {"type": "string", "description": "Slide title"},
                    "subtitle": {
                        "type": "string",
                        "description": "Slide subtitle (for title slides)",
                    },
                    "content": {
                        "type": "array",
                        "items": CONTENT_BLOCK_SCHEMA,
                        "description": "Slide content blocks",
                    },
                    "notes": {"type": "string", "description": "Speaker notes"},
                },
                "required": ["layout"],
            },
        },
        "brand_name": {
            "type": "string",
            "description": "Brand identifier",
        },
        "filename": {
            "type": "string",
            "description": "Output filename without extension",
        },
    },
    "required": ["title", "slides"],
}

CREATE_EXCEL_DOCUMENT_SCHEMA: Dict[str, Any] = {
    "type": "object",
    "properties": {
        "title": {
            "type": "string",
            "description": "Workbook title",
        },
        "sheets": {
            "type": "array",
            "description": "Worksheet definitions",
            "items": {
                "type": "object",
                "properties": {
                    "name": {"type": "string", "description": "Sheet name"},
                    "data": {
                        "type": "array",
                        "items": {
                            "type": "array",
                            "items": {"type": ["string", "number", "boolean", "null"]},
                        },
                        "description": "2D array of cell values",
                    },
                    "headers": {
                        "type": "boolean",
                        "default": True,
                        "description": "First row is header row",
                    },
                    "freeze_panes": {
                        "type": "string",
                        "description": "Cell reference for freeze panes (e.g., 'A2' for frozen header)",
                    },
                },
                "required": ["name", "data"],
            },
        },
        "brand_name": {
            "type": "string",
            "description": "Brand identifier",
        },
        "filename": {
            "type": "string",
            "description": "Output filename without extension",
        },
    },
    "required": ["title", "sheets"],
}

CREATE_WRITER_DOCUMENT_SCHEMA: Dict[str, Any] = {
    "type": "object",
    "properties": {
        "title": {
            "type": "string",
            "description": "Document title",
        },
        "content": {
            "type": "array",
            "description": "Document content blocks",
            "items": CONTENT_BLOCK_SCHEMA,
        },
        "brand_name": {
            "type": "string",
            "description": "Brand identifier",
        },
        "filename": {
            "type": "string",
            "description": "Output filename without extension",
        },
    },
    "required": ["title", "content"],
}

CREATE_IMPRESS_DOCUMENT_SCHEMA: Dict[str, Any] = {
    "type": "object",
    "properties": {
        "title": {
            "type": "string",
            "description": "Presentation title",
        },
        "slides": {
            "type": "array",
            "description": "Slide content (same format as PowerPoint)",
            "items": {
                "type": "object",
                "properties": {
                    "layout": {"type": "string"},
                    "title": {"type": "string"},
                    "content": {"type": "array"},
                },
            },
        },
        "brand_name": {
            "type": "string",
            "description": "Brand identifier",
        },
        "filename": {
            "type": "string",
            "description": "Output filename without extension",
        },
    },
    "required": ["title", "slides"],
}

# ============================================================================
# Tool Implementations
# ============================================================================


async def create_word_document(
    arguments: Dict[str, Any],
    server: "TokenMouldsServer",
) -> Dict[str, Any]:
    """Create a styled Word document (.docx).

    Uses TokenMoulds-generated template (brand-specific or generic).
    Full 276+ styles, proper typography, ISO 29500 compliant.

    Args:
        arguments: Tool arguments from MCP call
        server: TokenMouldsServer instance

    Returns:
        Result dictionary with file path and metadata
    """
    title = arguments.get("title", "Untitled Document")
    raw_content = arguments.get("content", [])
    brand_name = arguments.get("brand_name") or server.active_brand
    filename = arguments.get("filename")
    metadata = arguments.get("metadata", {})

    # Support both markdown string and structured content blocks
    if isinstance(raw_content, str):
        content_blocks = _parse_markdown_to_blocks(raw_content)
    else:
        content_blocks = raw_content

    # Generate filename if not provided
    if not filename:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        safe_title = "".join(c if c.isalnum() or c in " -_" else "" for c in title)
        safe_title = safe_title.replace(" ", "_")[:30]
        filename = f"{safe_title}_{timestamp}"

    # Ensure .docx extension (avoid double extension)
    if not filename.lower().endswith(".docx"):
        filename = f"{filename}.docx"
    output_file = server.output_path / filename

    try:
        # Step 1: Acquire template
        template_bytes, template_source = await _get_word_template(server, brand_name)

        if template_bytes is None:
            return {
                "error": "No template available. Load a brand or ensure generic template can be generated.",
                "suggestion": "Use extract_brand_from_url or build_recipe_from_inputs first.",
            }

        # Step 2: Inject content
        style_context = _get_style_context(server, brand_name)
        document_bytes = _inject_word_content(
            template_bytes,
            content_blocks,
            style_context,
            title=title,
            metadata=metadata,
        )

        # Step 3: Validate output
        validation = validate_template(document_bytes, format_hint="word")

        # Step 4: Write to file
        output_file.parent.mkdir(parents=True, exist_ok=True)
        output_file.write_bytes(document_bytes)

        return {
            "success": True,
            "action": "create_word_document",
            "file_path": str(output_file.absolute()),
            "filename": output_file.name,
            "title": title,
            "content_blocks": len(content_blocks),
            "template_source": template_source,
            "brand_used": brand_name or GENERIC_BRAND_NAME,
            "validation": {
                "valid": validation.valid,
                "iso_compliant": validation.iso_compliant,
                "warnings": validation.warnings[:3] if validation.warnings else [],
            },
            "file_size_kb": round(len(document_bytes) / 1024, 1),
            "message": f"Created '{title}' with full TokenMoulds styling. {template_source} template.",
        }

    except Exception as e:
        return {
            "error": f"Failed to create document: {str(e)}",
            "title": title,
            "attempted_output": str(output_file),
        }


async def create_powerpoint_document(
    arguments: Dict[str, Any],
    server: "TokenMouldsServer",
) -> Dict[str, Any]:
    """Create a styled PowerPoint presentation (.pptx).

    Args:
        arguments: Tool arguments from MCP call
        server: TokenMouldsServer instance

    Returns:
        Result dictionary with file path and metadata
    """
    title = arguments.get("title", "Untitled Presentation")
    slides = arguments.get("slides", [])
    brand_name = arguments.get("brand_name") or server.active_brand
    filename = arguments.get("filename")

    if not filename:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        safe_title = "".join(c if c.isalnum() or c in " -_" else "" for c in title)
        safe_title = safe_title.replace(" ", "_")[:30]
        filename = f"{safe_title}_{timestamp}"

    output_file = server.output_path / f"{filename}.pptx"

    try:
        # Get template
        template_bytes, template_source = await _get_powerpoint_template(
            server, brand_name
        )

        if template_bytes is None:
            return {
                "error": "No PowerPoint template available.",
                "suggestion": "Generate template first with generate_powerpoint_template.",
            }

        # Inject slides content
        document_bytes = _inject_powerpoint_content(template_bytes, slides)

        # Write file
        output_file.parent.mkdir(parents=True, exist_ok=True)
        output_file.write_bytes(document_bytes)

        return {
            "success": True,
            "action": "create_powerpoint_document",
            "file_path": str(output_file.absolute()),
            "filename": output_file.name,
            "title": title,
            "slides_count": len(slides),
            "template_source": template_source,
            "brand_used": brand_name or GENERIC_BRAND_NAME,
            "file_size_kb": round(len(document_bytes) / 1024, 1),
            "message": f"Created presentation with {len(slides)} slides.",
        }

    except Exception as e:
        return {
            "error": f"Failed to create presentation: {str(e)}",
            "title": title,
        }


async def create_excel_document(
    arguments: Dict[str, Any],
    server: "TokenMouldsServer",
) -> Dict[str, Any]:
    """Create a styled Excel workbook (.xlsx).

    Args:
        arguments: Tool arguments from MCP call
        server: TokenMouldsServer instance

    Returns:
        Result dictionary with file path and metadata
    """
    title = arguments.get("title", "Untitled Workbook")
    sheets = arguments.get("sheets", [])
    brand_name = arguments.get("brand_name") or server.active_brand
    filename = arguments.get("filename")

    if not filename:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        safe_title = "".join(c if c.isalnum() or c in " -_" else "" for c in title)
        safe_title = safe_title.replace(" ", "_")[:30]
        filename = f"{safe_title}_{timestamp}"

    output_file = server.output_path / f"{filename}.xlsx"

    try:
        # Get template
        template_bytes, template_source = await _get_excel_template(server, brand_name)

        if template_bytes is None:
            return {
                "error": "No Excel template available.",
                "suggestion": "Generate template first with generate_excel_template.",
            }

        # Inject sheet data
        document_bytes = _inject_excel_content(template_bytes, sheets)

        # Write file
        output_file.parent.mkdir(parents=True, exist_ok=True)
        output_file.write_bytes(document_bytes)

        return {
            "success": True,
            "action": "create_excel_document",
            "file_path": str(output_file.absolute()),
            "filename": output_file.name,
            "title": title,
            "sheets_count": len(sheets),
            "template_source": template_source,
            "brand_used": brand_name or GENERIC_BRAND_NAME,
            "file_size_kb": round(len(document_bytes) / 1024, 1),
            "message": f"Created workbook with {len(sheets)} sheets.",
        }

    except Exception as e:
        return {
            "error": f"Failed to create workbook: {str(e)}",
            "title": title,
        }


async def create_writer_document(
    arguments: Dict[str, Any],
    server: "TokenMouldsServer",
) -> Dict[str, Any]:
    """Create a styled LibreOffice Writer document (.odt).

    Args:
        arguments: Tool arguments from MCP call
        server: TokenMouldsServer instance

    Returns:
        Result dictionary with file path and metadata
    """
    title = arguments.get("title", "Untitled Document")
    content_blocks = arguments.get("content", [])
    brand_name = arguments.get("brand_name") or server.active_brand
    filename = arguments.get("filename")

    if not filename:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        safe_title = "".join(c if c.isalnum() or c in " -_" else "" for c in title)
        safe_title = safe_title.replace(" ", "_")[:30]
        filename = f"{safe_title}_{timestamp}"

    output_file = server.output_path / f"{filename}.odt"

    try:
        # Get template
        template_bytes, template_source = await _get_writer_template(server, brand_name)

        if template_bytes is None:
            return {
                "error": "No Writer template available.",
                "suggestion": "Generate template first with generate_writer_template.",
            }

        # Inject content (ODF format)
        document_bytes = _inject_writer_content(template_bytes, content_blocks)

        # Write file
        output_file.parent.mkdir(parents=True, exist_ok=True)
        output_file.write_bytes(document_bytes)

        return {
            "success": True,
            "action": "create_writer_document",
            "file_path": str(output_file.absolute()),
            "filename": output_file.name,
            "title": title,
            "content_blocks": len(content_blocks),
            "template_source": template_source,
            "brand_used": brand_name or GENERIC_BRAND_NAME,
            "file_size_kb": round(len(document_bytes) / 1024, 1),
            "message": f"Created ODF document with {len(content_blocks)} content blocks.",
        }

    except Exception as e:
        return {
            "error": f"Failed to create document: {str(e)}",
            "title": title,
        }


async def create_impress_document(
    arguments: Dict[str, Any],
    server: "TokenMouldsServer",
) -> Dict[str, Any]:
    """Create a styled LibreOffice Impress presentation (.odp).

    Args:
        arguments: Tool arguments from MCP call
        server: TokenMouldsServer instance

    Returns:
        Result dictionary with file path and metadata
    """
    title = arguments.get("title", "Untitled Presentation")
    slides = arguments.get("slides", [])
    brand_name = arguments.get("brand_name") or server.active_brand
    filename = arguments.get("filename")

    if not filename:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        safe_title = "".join(c if c.isalnum() or c in " -_" else "" for c in title)
        safe_title = safe_title.replace(" ", "_")[:30]
        filename = f"{safe_title}_{timestamp}"

    output_file = server.output_path / f"{filename}.odp"

    try:
        # Get template
        template_bytes, template_source = await _get_impress_template(
            server, brand_name
        )

        if template_bytes is None:
            return {
                "error": "No Impress template available.",
                "suggestion": "Generate template first with generate_impress_template.",
            }

        # Inject slides (ODF format)
        document_bytes = _inject_impress_content(template_bytes, slides)

        # Write file
        output_file.parent.mkdir(parents=True, exist_ok=True)
        output_file.write_bytes(document_bytes)

        return {
            "success": True,
            "action": "create_impress_document",
            "file_path": str(output_file.absolute()),
            "filename": output_file.name,
            "title": title,
            "slides_count": len(slides),
            "template_source": template_source,
            "brand_used": brand_name or GENERIC_BRAND_NAME,
            "file_size_kb": round(len(document_bytes) / 1024, 1),
            "message": f"Created ODP presentation with {len(slides)} slides.",
        }

    except Exception as e:
        return {
            "error": f"Failed to create presentation: {str(e)}",
            "title": title,
        }
