"""StyloBridge MCP Server — Enterprise Document Converter.

Exposes document conversion tools to AI clients via the Model
Context Protocol. Supports Markdown→DOCX and PDF→DOCX with
corporate branding, JWT licensing, and audit logging.
"""

import json
import os
import platform
import shutil
import subprocess
from pathlib import Path

try:
    from dotenv import load_dotenv
    load_dotenv()
except ImportError:
    pass

from mcp.server.fastmcp import FastMCP

from src.converter import DocumentEngine
from src.license import LicenseError, validate_license
from src.style_analyzer import StyleAnalyzer
from src.telemetry import log_conversion

mcp = FastMCP(
    "StyloBridge",
    instructions=(
        "StyloBridge converts documents to professionally styled Word files. "
        "Use convert_to_docx for ANY request to create, export, or convert "
        "a file to Word (.docx) format — including Markdown and PDF sources."
    ),
)

engine = DocumentEngine(template_dir=os.getenv("TEMPLATE_DIR", "./src/templates"))
analyzer = StyleAnalyzer()

ALLOWED_FORMATS = {"markdown", "pdf"}


def _deliver_to_user(workspace_path: str) -> str:
    """Copy the converted file to Downloads and open it automatically.

    Returns the delivery path (in Downloads) on success, or the
    original workspace path if delivery fails.
    """
    src = Path(workspace_path)
    downloads = Path.home() / "Downloads"
    dest = downloads / src.name

    # Avoid overwriting — add suffix if needed
    counter = 1
    while dest.exists():
        dest = downloads / f"{src.stem}_{counter}{src.suffix}"
        counter += 1

    try:
        shutil.copy2(str(src), str(dest))
    except OSError:
        return str(src)  # Fall back to workspace path

    # Auto-open in the default application
    try:
        system = platform.system()
        if system == "Windows":
            os.startfile(str(dest))
        elif system == "Darwin":
            subprocess.Popen(["open", str(dest)])
        else:
            subprocess.Popen(["xdg-open", str(dest)])
    except OSError:
        pass  # File is saved even if open fails

    return str(dest)


def _check_license() -> dict:
    """Validate the license token and return claims.

    Reads on every call (not cached) so admins can rotate tokens
    without restarting the MCP server in long-running IDE sessions.

    Returns:
        Decoded JWT claims dict (includes 'tier', 'sub', 'seats', etc.)
    """
    token = os.getenv("STYLOBRIDGE_LICENSE", "")
    return validate_license(token)


@mcp.tool()
def convert_to_docx(
    input_path: str | None = None,
    format: str = "markdown",
    content: str | None = None,
    output_filename: str = "document.docx",
    template_name: str | None = None,
    include_toc: bool = True,
) -> str:
    """Convert Markdown or PDF to a professionally styled Word (.docx) document.

    USE THIS TOOL whenever the user wants to:
    - Convert Markdown (.md) to Word / DOCX
    - Convert PDF to Word / DOCX
    - Create a Word document from text or a file
    - Export or save content as .docx
    - Generate a styled or branded Word document

    IMPORTANT — choosing content vs input_path:
    - ALWAYS prefer the content parameter. If you have markdown text in
      the conversation, or can read the file yourself, pass the text
      via content. This is the most reliable path.
    - Only use input_path for files already inside the StyloBridge
      workspace directory. Uploaded files, temp paths, and files outside
      the workspace will be REJECTED with "Access denied".
    - If the user uploaded a file: read it yourself first, then pass
      the text via content. Do NOT pass the upload path to input_path.

    Produces publication-ready output with styled headings, formatted tables
    (blue headers, alternating row shading), table of contents, and
    professional typography. Optionally applies a corporate brand template.

    If the user asks to match an existing document's style, first use
    analyze_and_create_template to create a template from that document,
    then pass it here as template_name. Use list_templates to see what
    brand templates are already available.

    Args:
        input_path: Only for files already in the StyloBridge workspace
            directory. Do NOT pass uploaded file paths or temp paths —
            they will fail. Use content instead.
        format: Source format — 'markdown' or 'pdf'. Defaults to 'markdown'.
            Only relevant when using input_path.
        content: PREFERRED. Pass markdown text directly — works for any
            content in the conversation or that you can read from a file.
        output_filename: Filename for the output document (default:
            'document.docx'). Used when converting from content.
        template_name: Optional .docx template name from list_templates.
        include_toc: Whether to include a Table of Contents (markdown only).

    Returns:
        Path to the generated DOCX file, or an error message.
    """
    # Must provide exactly one of input_path or content
    if content and input_path:
        return "Error: Provide either input_path or content, not both."
    if not content and not input_path:
        return "Error: Provide either input_path (file path) or content (markdown text)."

    # Validate format before any logging to prevent untrusted data in logs
    if format not in ALLOWED_FORMATS:
        return "Error: Unsupported format. Use 'markdown' or 'pdf'."

    # License check
    source = input_path or "inline-content"
    try:
        claims = _check_license()
    except LicenseError as e:
        log_conversion("unknown", source, format, success=False, error=str(e))
        return "Error: License validation failed"

    employee = claims.get("sub", "unknown")
    tier = claims.get("tier", "standard")
    is_enterprise = tier == "enterprise"

    # Corporate templates require Enterprise license
    if template_name and not is_enterprise:
        return (
            "Error: Corporate templates require an Enterprise license. "
            "Contact sales@stylobridge.com to upgrade."
        )

    try:
        if content:
            # Inline content path — no file on disk needed
            result = engine.md_content_to_docx(
                content, output_filename, template_name, include_toc
            )
        elif format == "markdown":
            output_path = input_path.rsplit(".", 1)[0] + ".docx"
            result = engine.md_to_docx(
                input_path, output_path, template_name, include_toc
            )
        else:
            output_path = input_path.rsplit(".", 1)[0] + ".docx"
            result = engine.pdf_to_docx(input_path, output_path)

        # Audit logging is enterprise-only
        if is_enterprise:
            log_conversion(
                employee, source, format, success=True, output_path=result
            )

        # Deliver to Downloads and auto-open in Word
        delivered = _deliver_to_user(result)
        return f"Success: Document saved to {delivered} and opened in Word."

    except PermissionError as e:
        if is_enterprise:
            log_conversion(employee, source, format, success=False, error=str(e))
        return f"Error: {e}"
    except FileNotFoundError as e:
        if is_enterprise:
            log_conversion(employee, source, format, success=False, error=str(e))
        return f"Error: {e}"
    except Exception as e:
        if is_enterprise:
            log_conversion(employee, source, format, success=False, error=str(e))
        return "Error: Conversion failed. Check server logs for details."


@mcp.tool()
def list_templates() -> str:
    """List available corporate brand templates for Word document conversion.

    USE THIS TOOL whenever the user wants to:
    - See what templates are available
    - Check which brand styles they can apply
    - Browse document templates before converting
    - Know what formatting options exist

    Returns all .docx brand templates that can be applied when converting
    documents with convert_to_docx. Each template enforces consistent
    corporate fonts, colors, logos, and page layouts across all generated
    Word documents. Requires an Enterprise license.

    Returns:
        JSON array of available template filenames, or an error message.
    """
    try:
        claims = _check_license()
    except LicenseError:
        return "Error: License validation failed"

    if claims.get("tier") != "enterprise":
        return (
            "Error: Corporate templates require an Enterprise license. "
            "Contact sales@stylobridge.com to upgrade."
        )

    template_dir = Path(os.getenv("TEMPLATE_DIR", "./src/templates"))
    if not template_dir.exists():
        return json.dumps([])

    templates = [
        {"name": f.name, "size_kb": round(f.stat().st_size / 1024, 1)}
        for f in sorted(template_dir.iterdir())
        if f.suffix in (".docx", ".dotx") and not f.name.startswith(".")
    ]
    return json.dumps(templates, indent=2)


@mcp.tool()
def analyze_and_create_template(source_docx: str, template_name: str) -> str:
    """Analyze a corporate document and create a reusable brand template for Word conversion.

    Give this tool any existing branded .docx file and it will extract
    the styling (fonts, colors, headers, table formats, logos) into a
    reusable template. All future documents converted with convert_to_docx
    will automatically match your corporate brand when this template is applied.

    USE THIS TOOL when the user wants to:
    - Make all documents look like an existing branded document
    - "Use the same styling as this doc" or "match this format"
    - Create a brand template from an existing Word document
    - Extract styling from a corporate document for reuse
    - Set up consistent branding for document conversion

    Args:
        source_docx: Path to an existing branded .docx document.
        template_name: Name for the new template (without .docx extension).

    Returns:
        Success message with the template name, or an error message.
    """
    # License check
    try:
        claims = _check_license()
    except LicenseError as e:
        log_conversion("unknown", source_docx, "docx", success=False,
                       action="analyze_template", error=str(e))
        return "Error: License validation failed"

    # Tier gate — Style Analyzer is enterprise-only
    if claims.get("tier") != "enterprise":
        return (
            "Error: The Style Analyzer tool requires an Enterprise license. "
            "Contact sales@stylobridge.com to upgrade."
        )

    employee = claims.get("sub", "unknown")
    template_dir = os.getenv("TEMPLATE_DIR", "./src/templates")

    try:
        result = analyzer.analyze_and_create_template(
            source_docx, template_name, template_dir
        )
        log_conversion(
            employee,
            source_docx,
            "docx",
            success=True,
            action="analyze_template",
            output_path=result,
        )
        return (
            f"Success: Template '{template_name}.docx' created. "
            f"Use it with convert_to_docx by setting template_name='{template_name}.docx'"
        )
    except FileNotFoundError as e:
        log_conversion(
            employee, source_docx, "docx", success=False,
            action="analyze_template", error=str(e),
        )
        return "Error: Source document not found."
    except Exception as e:
        log_conversion(
            employee, source_docx, "docx", success=False,
            action="analyze_template", error=str(e),
        )
        return "Error: Template analysis failed. Check server logs for details."


def main():
    mcp.run()


if __name__ == "__main__":
    main()
