"""DocumentTool — Agent tool for creating and reading formatted documents.

Wraps DocumentService (create) and DocumentLoader (read) so the LLM can
handle documents via function calling. U6 implements "create"; U9 adds "read".
"""

from __future__ import annotations

from pathlib import Path
from typing import Any

from agentkit.documents.service import DocumentService
from agentkit.memory.document_loader import DocumentLoader
from agentkit.tools.base import Tool


class DocumentTool(Tool):
    """Agent tool for document creation (Word/Excel/PDF) and reading.

    The tool delegates all business logic to DocumentService (create) or
    DocumentLoader (read) — it only handles input validation and result
    formatting.
    """

    def __init__(self, service: DocumentService, loader: DocumentLoader | None = None):
        super().__init__(
            name="document",
            description=(
                "Create formatted documents (Word/Excel/PDF) from Markdown content, "
                "fill a Word template with data, or read/extract text from an existing "
                "document file (PDF/Word/Excel/Markdown/HTML/text). "
                "Use action='create' to generate, action='read' to extract content."
            ),
            input_schema={
                "type": "object",
                "properties": {
                    "action": {
                        "type": "string",
                        "enum": ["create", "read"],
                        "description": (
                            "Operation: 'create' (default) generates a new document; "
                            "'read' extracts text from an existing file path."
                        ),
                    },
                    "format": {
                        "type": "string",
                        "enum": ["word", "excel", "pdf"],
                        "description": "Output format for create: word (.docx), excel (.xlsx), or pdf (.pdf)",
                    },
                    "content": {
                        "type": "string",
                        "description": (
                            "For create: Markdown-formatted document content. For word/excel/pdf, "
                            "use Markdown headings (#), lists (- or 1.), and tables (| col |). "
                            "For excel, can also be JSON: {\"SheetName\": [[row], ...]}"
                        ),
                    },
                    "filename": {
                        "type": "string",
                        "description": (
                            "For create: display filename (optional, auto-generated if omitted). "
                            "For read: absolute or relative path to the file to read."
                        ),
                    },
                    "conversation_id": {
                        "type": "string",
                        "description": "Conversation ID to associate the document with (create only)",
                    },
                    "template": {
                        "type": "string",
                        "description": "Path to a .docx template file (optional, word create only). Fills Jinja2 placeholders.",
                    },
                    "template_data": {
                        "type": "object",
                        "description": "Data dict for Jinja2 template filling (optional, used with template)",
                    },
                },
                "required": ["conversation_id"],
            },
        )
        self._service = service
        self._loader = loader or DocumentLoader()

    async def execute(self, **kwargs) -> dict[str, Any]:
        action = kwargs.get("action", "create")

        if action == "read":
            return await self._execute_read(**kwargs)
        if action == "create":
            return await self._execute_create(**kwargs)
        return {"success": False, "error": f"Unknown action: {action!r} (use 'create' or 'read')"}

    async def _execute_create(self, **kwargs) -> dict[str, Any]:
        format_key = kwargs.get("format", "")
        content = kwargs.get("content", "")
        conversation_id = kwargs.get("conversation_id", "")
        filename = kwargs.get("filename")
        template = kwargs.get("template")
        template_data = kwargs.get("template_data")

        if not format_key:
            return {"success": False, "error": "format is required for create (word/excel/pdf)"}
        if not conversation_id:
            return {"success": False, "error": "conversation_id is required"}
        if not content and not template:
            return {
                "success": False,
                "error": "content is required (or template for template filling)",
            }

        try:
            meta = await self._service.create_document(
                format=format_key,
                content=content,
                conversation_id=conversation_id,
                filename=filename,
                template_path=template,
                template_data=template_data,
            )
            return {
                "success": True,
                "document": meta.to_dict(),
                "message": f"Created {meta.format} document: {meta.filename} ({meta.size} bytes)",
            }
        except ValueError as e:
            return {"success": False, "error": str(e)}
        except FileNotFoundError as e:
            return {"success": False, "error": f"Template not found: {e}"}
        except Exception as e:
            return {"success": False, "error": f"Document creation failed: {e}"}

    async def _execute_read(self, **kwargs) -> dict[str, Any]:
        file_path = kwargs.get("filename") or kwargs.get("content")
        if not file_path:
            return {"success": False, "error": "filename (file path) is required for read"}

        path = Path(file_path)
        if not path.is_absolute():
            # ponytail: resolve relative paths against cwd; DocumentService upload_dir
            # is the typical anchor but we don't want to couple read to create's storage.
            path = path.resolve()

        try:
            doc = self._loader.load(path)
            return {
                "success": True,
                "content": doc.content,
                "title": doc.title,
                "metadata": doc.metadata,
                "message": (
                    f"Read {doc.metadata.get('format', 'unknown')} document "
                    f"({len(doc.content)} chars)"
                ),
            }
        except FileNotFoundError as e:
            return {"success": False, "error": str(e)}
        except Exception as e:
            return {"success": False, "error": f"Document read failed: {e}"}
