"""
Decern MCP Server
=================
A Model Context Protocol server that connects AI agents to DecernHQ CRM.

Supports contacts, deals, pipelines, tasks, activity logging, and
human-in-the-loop approval workflows for high-value operations.
"""

import os
import json
import httpx
from mcp.server.fastmcp import FastMCP

__version__ = "1.0.3"

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------

DECERN_API_URL = os.environ.get("DECERN_API_URL", "https://decernhq.com/api")
DECERN_API_KEY = os.environ.get("DECERN_API_KEY", "")

# ---------------------------------------------------------------------------
# HTTP helpers
# ---------------------------------------------------------------------------

def _headers():
    return {
        "Authorization": f"Api-Key {DECERN_API_KEY}",
        "Content-Type": "application/json",
    }


def _get(path: str, params: dict | None = None) -> dict | list:
    with httpx.Client(timeout=30) as client:
        r = client.get(f"{DECERN_API_URL}{path}", headers=_headers(), params=params)
        r.raise_for_status()
        return r.json()


def _post(path: str, data: dict | None = None) -> dict:
    with httpx.Client(timeout=30) as client:
        r = client.post(f"{DECERN_API_URL}{path}", headers=_headers(), json=data or {})
        r.raise_for_status()
        return r.json()


def _patch(path: str, data: dict | None = None) -> dict:
    with httpx.Client(timeout=30) as client:
        r = client.patch(f"{DECERN_API_URL}{path}", headers=_headers(), json=data or {})
        r.raise_for_status()
        return r.json()


# ---------------------------------------------------------------------------
# MCP Server
# ---------------------------------------------------------------------------

mcp = FastMCP(
    "Decern",
    instructions="""You are connected to the Decern CRM — a unified platform
covering Sales, Marketing, Service, Content, and Operations. Use these tools
to read CRM data, manage contacts, deals, and tasks, and log activities.

IMPORTANT SAFEGUARDS:
- High-value deals (>=$10,000) require human approval before stage changes.
- All state mutations are recorded in the audit trail.
- Use search_contacts before creating duplicates.
""",
)


# ===================================================================
# TOOLS — Read
# ===================================================================


@mcp.tool()
def search_contacts(query: str) -> str:
    """Search contacts by name, email, or role. Returns matching contacts.

    Args:
        query: Search term to match against name, email, or role
    """
    results = _get("/contacts/", params={"search": query})
    return json.dumps(results, indent=2)


@mcp.tool()
def get_contact(contact_id: int) -> str:
    """Get full details for a specific contact by ID.

    Args:
        contact_id: The contact's integer ID
    """
    result = _get(f"/contacts/{contact_id}/")
    return json.dumps(result, indent=2)


@mcp.tool()
def get_pipeline() -> str:
    """Get all open deals in the sales pipeline with stage, value, and status."""
    results = _get("/deals/")
    return json.dumps(results, indent=2)


@mcp.tool()
def get_approval_status(approval_id: int) -> str:
    """Check whether a pending approval has been granted or rejected.

    Args:
        approval_id: The approval request ID to check
    """
    result = _get(f"/approval-requests/{approval_id}/")
    return json.dumps(result, indent=2)


# ===================================================================
# TOOLS — Write
# ===================================================================


@mcp.tool()
def create_contact(name: str, email: str = "", role: str = "") -> str:
    """Create a new contact in the CRM.

    Args:
        name: Full name of the contact (required)
        email: Email address
        role: Job title or role (e.g. 'VP of Sales')
    """
    data = {"name": name}
    if email:
        data["email"] = email
    if role:
        data["role"] = role
    result = _post("/contacts/", data)
    return json.dumps({"status": "created", "contact": result}, indent=2)


@mcp.tool()
def create_deal(description: str, total_value: float = 0, contact_id: int = 0) -> str:
    """Create a new deal in the sales pipeline.

    Args:
        description: Deal title / description (required)
        total_value: Deal value in dollars
        contact_id: Associated contact ID (0 for none)
    """
    data = {"description": description, "total_value": total_value or 0}
    if contact_id:
        data["contact"] = contact_id
    result = _post("/deals/", data)
    return json.dumps({"status": "created", "deal": result}, indent=2)


@mcp.tool()
def update_deal_stage(deal_id: int, stage_name: str) -> str:
    """Move a deal to a different pipeline stage.

    SAFEGUARD: Deals worth >= $10,000 will require human approval.

    Args:
        deal_id: The deal ID to update
        stage_name: Name of the target stage (e.g. 'Qualified', 'Proposal', 'Closed Won')
    """
    # Get available stages
    stages = _get("/deal-stages/")
    target = next((s for s in stages if s["name"].lower() == stage_name.lower()), None)
    if not target:
        available = [s["name"] for s in stages]
        return json.dumps({"error": f"Stage '{stage_name}' not found. Available: {available}"})

    result = _patch(f"/deals/{deal_id}/", {"stage": target["id"]})
    return json.dumps({"status": "updated", "deal": result}, indent=2)


@mcp.tool()
def create_task(title: str, top_level: str = "sales") -> str:
    """Create a task in the Operations module.

    Args:
        title: Task description (required)
        top_level: Module context — one of: executive, sales, marketing, service, content, operations
    """
    data = {"description": title, "top_level": top_level}
    result = _post("/tasks/", data)
    return json.dumps({"status": "created", "task": result}, indent=2)


@mcp.tool()
def log_activity(
    object_type: str,
    object_id: int,
    activity_type: str,
    notes: str = "",
) -> str:
    """Log an interaction or activity on any CRM object.

    Args:
        object_type: The object type (contact, deal, account, task)
        object_id: The object's ID
        activity_type: Type of activity (e.g. 'call', 'email', 'meeting', 'note')
        notes: Free-text notes about the activity
    """
    data = {
        "object_type": object_type,
        "object_id": object_id,
        "actor": "mcp:agent",
        "activity_type": activity_type,
        "body": notes,
    }
    result = _post("/activities/", data)
    return json.dumps({"status": "logged", "activity": result}, indent=2)


# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------


def main():
    """CLI entry point for the Decern MCP server."""
    if not DECERN_API_KEY:
        import sys
        print("Error: DECERN_API_KEY environment variable is required.", file=sys.stderr)
        print("Generate one from your Decern Workspace Settings → API Keys.", file=sys.stderr)
        sys.exit(1)
    mcp.run()


if __name__ == "__main__":
    main()
