"""Lucidchart MCP tools (DataBridge AI)."""
from __future__ import annotations

import json
import os
from pathlib import Path
from typing import Any, Dict, Optional
from datetime import datetime

import requests


def _lucid_config() -> Dict[str, str]:
    return {
        "base_url": os.getenv("LUCID_API_BASE", "https://api.lucid.co").rstrip("/"),
        "api_version": os.getenv("LUCID_API_VERSION", "1"),
        "api_key": os.getenv("LUCID_API_KEY", ""),
        "token": os.getenv("LUCID_AUTH_TOKEN", ""),
    }


def _auth_headers() -> Dict[str, str]:
    cfg = _lucid_config()
    token = cfg["token"] or cfg["api_key"]
    if not token:
        return {}
    return {
        "Authorization": f"Bearer {token}",
        "Lucid-Api-Version": cfg["api_version"],
    }


def _lucid_request(
    method: str,
    path: str,
    *,
    params: Optional[Dict[str, Any]] = None,
    json_body: Optional[Dict[str, Any]] = None,
    headers: Optional[Dict[str, str]] = None,
    files: Optional[Dict[str, Any]] = None,
    data: Optional[Dict[str, Any]] = None,
    stream: bool = False,
) -> Dict[str, Any]:
    cfg = _lucid_config()
    base = cfg["base_url"]
    url = f"{base}{path}"
    merged_headers = {**_auth_headers(), **(headers or {})}

    resp = requests.request(
        method=method,
        url=url,
        params=params,
        json=json_body,
        headers=merged_headers,
        files=files,
        data=data,
        stream=stream,
        timeout=60,
    )
    content_type = resp.headers.get("Content-Type", "")
    if stream:
        return {"status_code": resp.status_code, "ok": resp.ok, "content_type": content_type, "raw": resp.content}
    try:
        payload = resp.json()
    except Exception:
        payload = {"raw": resp.text}
    return {
        "status_code": resp.status_code,
        "ok": resp.ok,
        "content_type": content_type,
        "data": payload,
    }


def register_lucidchart_tools(mcp, settings):
    """Register Lucidchart MCP tools."""

    @mcp.tool()
    def lucid_search_documents(
        keywords: str = "",
        limit: int = 20,
        offset: int = 0,
        request_json: Optional[str] = None,
    ) -> Dict[str, Any]:
        """
        Search Lucid documents the user can access.

        If request_json is provided, it will be used as the POST body verbatim.
        Otherwise, a minimal body using keywords/limit/offset is sent.
        """
        if request_json:
            body = json.loads(request_json)
        else:
            body = {"keywords": keywords, "limit": limit, "offset": offset}
        return _lucid_request("POST", "/documents/search", json_body=body)

    @mcp.tool()
    def lucid_get_document(document_id: str) -> Dict[str, Any]:
        """Get document metadata by ID."""
        return _lucid_request("GET", f"/documents/{document_id}")

    @mcp.tool()
    def lucid_get_document_contents(document_id: str) -> Dict[str, Any]:
        """Get document contents JSON by ID."""
        return _lucid_request("GET", f"/documents/{document_id}/contents")

    @mcp.tool()
    def lucid_export_document(
        document_id: str,
        export_format: str = "pdf",
        output_path: str = "",
    ) -> Dict[str, Any]:
        """
        Export a document in a specified format.

        export_format: pdf | png | jpeg | svg (depends on Lucid support)
        """
        accept_map = {
            "pdf": "application/pdf",
            "png": "image/png",
            "jpeg": "image/jpeg",
            "jpg": "image/jpeg",
            "svg": "image/svg+xml",
        }
        accept = accept_map.get(export_format.lower(), "application/pdf")
        response = _lucid_request(
            "GET",
            f"/documents/{document_id}",
            headers={"Accept": accept},
            stream=True,
        )
        if output_path:
            path = Path(output_path)
            path.parent.mkdir(parents=True, exist_ok=True)
            path.write_bytes(response.get("raw", b""))
            response["saved_to"] = str(path)
        return response

    @mcp.tool()
    def lucid_create_document(
        title: str,
        product: str = "lucidchart",
        parent: Optional[int] = None,
    ) -> Dict[str, Any]:
        """Create a new Lucid document."""
        body = {"title": title, "product": product}
        if parent is not None:
            body["parent"] = parent
        return _lucid_request("POST", "/documents", json_body=body)

    @mcp.tool()
    def lucid_copy_document(
        template_document_id: str,
        title: str,
        parent: Optional[int] = None,
    ) -> Dict[str, Any]:
        """Copy an existing Lucid document by template ID."""
        body = {"title": title, "template": template_document_id}
        if parent is not None:
            body["parent"] = parent
        return _lucid_request("POST", "/documents", json_body=body)

    @mcp.tool()
    def lucid_import_document(
        file_path: str,
        product: str = "lucidchart",
        title: Optional[str] = None,
        parent: Optional[int] = None,
        file_type: str = "x-application/vnd.lucid.standardImport",
    ) -> Dict[str, Any]:
        """
        Import an external file as a new Lucid document.

        Use file_type for standard import: x-application/vnd.lucid.standardImport
        """
        path = Path(file_path)
        if not path.exists():
            return {"ok": False, "error": f"File not found: {file_path}"}
        data = {"product": product, "type": file_type}
        if title:
            data["title"] = title
        if parent is not None:
            data["parent"] = str(parent)
        with path.open("rb") as f:
            files = {"file": (path.name, f, file_type)}
            return _lucid_request("POST", "/documents", files=files, data=data)

    @mcp.tool()
    def publish_databridge_workflow_to_lucid(
        project_name: str = "DataBridge AI",
        phase: str = "Current",
        include_dbt: bool = True,
        include_lineage: bool = True,
    ) -> Dict[str, Any]:
        """
        Create a Lucid document and package current DataBridge workflow documentation.
        """
        title = f"{project_name} Workflow - {phase}"
        create_resp = _lucid_request(
            "POST",
            "/documents",
            json_body={"title": title, "product": "lucidchart"},
        )
        if not create_resp.get("ok"):
            return {
                "status": "error",
                "stage": "create_document",
                "response": create_resp,
            }

        doc = create_resp.get("data", {})
        doc_id = doc.get("documentId")

        root = Path(settings.data_dir)
        docs_root = Path("docs")
        package_dir = root / "lucid_exports"
        package_dir.mkdir(parents=True, exist_ok=True)
        stamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S")
        summary_path = package_dir / f"lucid_databridge_summary_{stamp}.md"
        manifest_path = package_dir / f"lucid_databridge_manifest_{stamp}.json"

        sources = [
            docs_root / "DataBridge_AI_Full_Workflow.md",
            docs_root / "DataBridge_AI_Data_Modeling_Plugin.md",
            docs_root / "DataBridge_AI_Workflow_Diagrams.html",
        ]
        if include_dbt:
            sources.extend([
                Path("data/dbt_projects/snowflake_data_model/target/run_results.json"),
                Path("data/dbt_projects/snowflake_data_model/target/manifest.json"),
                Path("data/dbt_projects/snowflake_data_model/target/catalog.json"),
            ])
        if include_lineage:
            sources.append(Path("data/data_modeling/latest_run.json"))

        existing = [p for p in sources if p.exists()]

        lines = [
            f"# {title}",
            "",
            f"- Generated: {datetime.utcnow().isoformat()}Z",
            f"- Lucid document ID: {doc_id}",
            f"- Lucid edit URL: {doc.get('editUrl', '')}",
            "",
            "## Source Files",
        ]
        for p in existing:
            lines.append(f"- {p}")

        for p in existing:
            lines.append("")
            lines.append(f"## Excerpt: {p.name}")
            text = p.read_text(encoding="utf-8", errors="ignore")
            lines.append(text[:4000])

        summary_path.write_text("\n".join(lines), encoding="utf-8")
        manifest_payload = {
            "project_name": project_name,
            "phase": phase,
            "document": doc,
            "summary_path": str(summary_path),
            "sources": [str(p) for p in existing],
            "notes": [
                "Lucid API create/get/contents are active.",
                "Direct import requires Lucid-supported import file types.",
                "Use summary + source set to complete diagram authoring in Lucid.",
            ],
        }
        manifest_path.write_text(json.dumps(manifest_payload, indent=2), encoding="utf-8")

        return {
            "status": "completed",
            "document": doc,
            "summary_path": str(summary_path),
            "manifest_path": str(manifest_path),
            "sources_included": len(existing),
        }

    return {
        "tools_registered": 8,
        "tools": [
            "lucid_search_documents",
            "lucid_get_document",
            "lucid_get_document_contents",
            "lucid_export_document",
            "lucid_create_document",
            "lucid_copy_document",
            "lucid_import_document",
            "publish_databridge_workflow_to_lucid",
        ],
    }
