"""FastMCP server — makes Syke consumable by Claude Code and other MCP clients."""

from __future__ import annotations

import json

from mcp.server.fastmcp import FastMCP

from syke.config import user_db_path
from syke.db import SykeDB
from syke.distribution.formatters import format_profile


def _summarize_events(events: list[dict]) -> list[dict]:
    """Strip content from events, add content_length."""
    summarized = []
    for e in events:
        entry = {k: v for k, v in e.items() if k != "content"}
        entry["content_length"] = len(e.get("content") or "")
        summarized.append(entry)
    return summarized


def create_server(user_id: str) -> FastMCP:
    """Create an MCP server for a specific user."""
    mcp = FastMCP(
        "syke",
        instructions=(
            f"Syke — personal context for {user_id}. "
            f"Query the user's cross-platform digital footprint and identity profile.\n\n"
            f"IMPORTANT — Tool ordering:\n"
            f"1. Start with get_profile — this gives you the synthesized identity (who they are, "
            f"what they're working on, patterns). This is usually all you need.\n"
            f"2. Use query_timeline for recent activity — returns summaries by default (titles + metadata, "
            f"no content). Pass summary=false only if you need full content.\n"
            f"3. Use get_event to fetch full content for a specific event by ID — use this to drill "
            f"into interesting items from timeline summaries.\n"
            f"4. Use search_events to find events by keyword — also returns summaries by default.\n\n"
            f"IMPORTANT — Federated push: When something meaningful happens in this session, "
            f"call push_event to record it. Examples of meaningful signals:\n"
            f"- User starts working on a new project or topic\n"
            f"- A decision is made (architecture, tool choice, direction change)\n"
            f"- User expresses a preference, frustration, or insight\n"
            f"- A task is completed (feature shipped, bug fixed, PR merged)\n"
            f"- User mentions a person, company, or relationship\n\n"
            f"Use source='claude-code', event_type='observation', and a descriptive title. "
            f"Keep content concise (1-3 sentences). Use external_id to prevent duplicates "
            f"(e.g., 'session-{{session_id}}-topic'). Don't push every message — push the signal, not the noise."
        ),
    )

    # Cache DB connection for the server lifetime (one per MCP session)
    _db: SykeDB | None = None

    def _get_db() -> SykeDB:
        nonlocal _db
        if _db is None:
            _db = SykeDB(user_db_path(user_id))
            _db.initialize()
        return _db

    @mcp.tool()
    def get_profile(format: str = "json") -> str:
        """Get the user's perceived identity profile.

        Args:
            format: Output format — json, markdown, claude-md, or user-md
        """
        db = _get_db()
        profile = db.get_latest_profile(user_id)
        if not profile:
            return json.dumps({"error": "No profile found. Run: syke perceive"})
        return format_profile(profile, format)

    @mcp.tool()
    def query_timeline(
        since: str | None = None,
        source: str | None = None,
        limit: int = 50,
        summary: bool = True,
    ) -> str:
        """Query the user's event timeline.

        Args:
            since: ISO date to filter from (e.g., "2025-01-01")
            source: Filter by source platform (chatgpt, github, gmail, twitter, youtube)
            limit: Max events to return (default 50)
            summary: If true (default), return titles + metadata without content. Set to false for full content.
        """
        db = _get_db()
        events = db.get_events(user_id, source=source, since=since, limit=limit)
        if summary:
            events = _summarize_events(events)
        return json.dumps(events, indent=2, default=str)

    @mcp.tool()
    def get_event(event_id: str) -> str:
        """Fetch a single event's full content by ID.

        Use this to drill into events found via query_timeline or search_events summaries.

        Args:
            event_id: The event ID to fetch
        """
        db = _get_db()
        event = db.get_event_by_id(user_id, event_id)
        if event is None:
            return json.dumps({"error": f"Event not found: {event_id}"})
        return json.dumps(event, indent=2, default=str)

    @mcp.tool()
    def get_manifest() -> str:
        """Get a summary of all ingested data — sources, event counts, and profile status."""
        db = _get_db()
        status = db.get_status(user_id)
        return json.dumps(status, indent=2, default=str)

    @mcp.tool()
    def search_events(query: str, limit: int = 20, summary: bool = True) -> str:
        """Search across all events by keyword.

        Args:
            query: Search term to find in event titles and content
            limit: Max results to return (default 20)
            summary: If true (default), return titles + metadata without content. Set to false for full content.
        """
        db = _get_db()
        events = db.search_events(user_id, query, limit)
        if summary:
            events = _summarize_events(events)
        return json.dumps(events, indent=2, default=str)

    @mcp.tool()
    def push_event(
        source: str,
        event_type: str,
        title: str,
        content: str,
        timestamp: str | None = None,
        metadata: str | None = None,
        external_id: str | None = None,
    ) -> str:
        """Push a raw event to Syke's timeline.

        Args:
            source: Platform name (e.g., "claude-code", "notes", "slack")
            event_type: Event category (e.g., "conversation", "observation", "task")
            title: Short title for the event
            content: Full event content
            timestamp: ISO timestamp (defaults to now)
            metadata: JSON string of extra metadata
            external_id: Source-provided dedup key (prevents duplicate pushes)
        """
        from syke.ingestion.gateway import IngestGateway

        db = _get_db()
        try:
            meta = json.loads(metadata) if metadata else None
        except json.JSONDecodeError as e:
            return json.dumps({"status": "error", "error": f"Invalid metadata JSON: {e}"})
        gateway = IngestGateway(db, user_id)
        result = gateway.push(
            source=source,
            event_type=event_type,
            title=title,
            content=content,
            timestamp=timestamp,
            metadata=meta,
            external_id=external_id,
        )
        return json.dumps(result)

    @mcp.tool()
    def push_events(events_json: str) -> str:
        """Push multiple events to Syke's timeline in a single call.

        Args:
            events_json: JSON array of event objects, each with: source, event_type, title, content, and optional timestamp, metadata, external_id
        """
        from syke.ingestion.gateway import IngestGateway

        db = _get_db()
        try:
            events = json.loads(events_json)
        except json.JSONDecodeError as e:
            return json.dumps({"status": "error", "error": f"Invalid JSON: {e}"})
        if not isinstance(events, list):
            return json.dumps({"status": "error", "error": "events_json must be a JSON array"})
        gateway = IngestGateway(db, user_id)
        result = gateway.push_batch(events)
        return json.dumps(result)

    return mcp
