#!/usr/bin/env python3
"""
COS MCP Server - Model Context Protocol server for COS analysis tools.

Provides Claude Desktop, Claude Code, and other MCP clients access to COS
communication analysis capabilities across 7 psychology frameworks.

Usage:
    # Via uvx (recommended)
    uvx cos-mcp

    # Via pip
    pip install cos-mcp
    cos-mcp

    # Direct run
    python -m cos_mcp

Environment variables:
    COS_API_KEY: Your COS developer API key (required)
    COS_API_URL: COS API base URL (default: https://semalytics.com/api)
"""

import os
import httpx
from typing import Literal
from fastmcp import FastMCP

from cos_mcp import __version__

# Configuration
COS_API_URL = os.environ.get("COS_API_URL", "https://semalytics.com/api")
COS_API_KEY = os.environ.get("COS_API_KEY", "")
TIMEOUT = 60.0  # Analysis can take time

# Initialize MCP server
mcp = FastMCP(
    name="COS Analysis Server",
    version=__version__,
    instructions="""You have access to COS (Communication Optimization System) -
    a professional communication analysis platform. Use these tools to analyze
    content for engagement, personality fit, strategic clarity, and cognitive framing.

    Core 4 frameworks:
    - Engagement Analysis: Emotional engagement scoring (impact, novelty, relevance)
    - Personality Analysis: Personality-based communication (OCEAN model)
    - Strategic Clarity: Business message alignment (value prop, differentiation, CTA)
    - Framing Strategy: Cognitive frames and power positioning

    Extended 3 frameworks:
    - Persuasion Analysis: Domain-specific (business, politics, health, masculinity, comedy)
    - Platform Analysis: Platform-specific optimization (13 platforms)
    - Quality Analysis: 5-dimension quality assessment

    Best practices:
    - Use analyze_content for core 4-framework analysis
    - Use analyze_full_comms for comprehensive 7-framework analysis
    - Use analyze_persuasion/platform/quality for targeted extended analysis
    - Check get_templates for pre-built analysis scenarios
    - Always specify platform and target_audience for best results
    """
)


def _get_headers() -> dict:
    """Get auth headers for COS API calls."""
    headers = {"Accept": "application/json", "Content-Type": "application/json"}
    if COS_API_KEY:
        headers["Authorization"] = f"Bearer {COS_API_KEY}"
    return headers


FrameworkType = Literal["hape", "big_five", "strategic_clarity", "framing_strategy"]
PlatformType = Literal[
    "twitter", "linkedin", "email", "youtube", "tiktok",
    "instagram", "facebook", "medium", "substack", "podcast",
    "newsletter", "slack", "discord", "general"
]


@mcp.tool
async def analyze_content(
    content: str,
    platform: PlatformType = "general",
    target_audience: str | None = None,
) -> dict:
    """
    Analyze content using all 4 COS frameworks in parallel.

    Returns comprehensive analysis with:
    - Overall scores (0-10) for each framework
    - Dimension breakdowns with weights
    - Specific recommendations for improvement
    - Cross-framework insights

    Args:
        content: The text content to analyze (min 50 characters)
        platform: Target platform for optimization (affects scoring weights)
        target_audience: Description of intended audience (improves relevance scoring)

    Returns:
        Full analysis results from HAPE, Big Five, Strategic Clarity, and Framing Strategy
    """
    if len(content) < 50:
        return {"error": "Content must be at least 50 characters for meaningful analysis"}

    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.post(
            f"{COS_API_URL}/analyze/full",
            json={
                "content": content,
                "platform": platform,
                "target_audience": target_audience,
            }
        )

        if response.status_code != 200:
            return {"error": f"Analysis failed: {response.text}"}

        return response.json()


@mcp.tool
async def analyze_framework(
    content: str,
    framework: FrameworkType,
    platform: PlatformType = "general",
    target_audience: str | None = None,
) -> dict:
    """
    Analyze content using a single specific framework.

    Faster than full analysis when you only need one perspective.

    Frameworks:
    - hape: Engagement Analysis (novelty, relevance, emotional valence)
    - big_five: Personality Analysis using OCEAN model (openness, conscientiousness, extraversion, agreeableness, neuroticism)
    - strategic_clarity: Business message clarity (value prop, differentiation, CTA)
    - framing_strategy: Cognitive frames and power positioning

    Args:
        content: The text content to analyze (min 50 characters)
        framework: Which analysis framework to use
        platform: Target platform for optimization
        target_audience: Description of intended audience

    Returns:
        Single framework analysis with score, dimensions, and recommendations
    """
    if len(content) < 50:
        return {"error": "Content must be at least 50 characters for meaningful analysis"}

    endpoint_map = {
        "hape": "hape",
        "big_five": "big-five",
        "strategic_clarity": "strategic-clarity",
        "framing_strategy": "framing-strategy",
    }

    endpoint = endpoint_map.get(framework)
    if not endpoint:
        return {"error": f"Unknown framework: {framework}"}

    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.post(
            f"{COS_API_URL}/analyze/{endpoint}",
            json={
                "content": content,
                "platform": platform,
                "target_audience": target_audience,
            }
        )

        if response.status_code != 200:
            return {"error": f"Analysis failed: {response.text}"}

        return response.json()


@mcp.tool
async def get_templates(
    category: str | None = None,
    search: str | None = None,
) -> dict:
    """
    List available analysis templates.

    Templates are pre-configured analysis scenarios for common use cases:
    - Email outreach optimization
    - LinkedIn post analysis
    - Sales pitch review
    - Content marketing assessment

    Args:
        category: Filter by template category (e.g., "email", "social", "sales")
        search: Search templates by name or description

    Returns:
        List of templates with id, name, description, and required variables
    """
    params = {}
    if category:
        params["category"] = category
    if search:
        params["search"] = search

    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.get(
            f"{COS_API_URL}/templates/",
            params=params,
        )

        if response.status_code != 200:
            return {"error": f"Failed to fetch templates: {response.text}"}

        return response.json()


@mcp.tool
async def execute_template(
    template_id: str,
    variables: dict,
    platform: PlatformType = "general",
) -> dict:
    """
    Execute a specific template with provided variables.

    Templates guide the analysis with pre-defined prompts and variable placeholders.
    First use get_templates to find available templates and their required variables.

    Args:
        template_id: The template ID to execute (from get_templates)
        variables: Dictionary of variable values required by the template
        platform: Target platform for optimization

    Returns:
        Template execution results with analysis and recommendations
    """
    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.post(
            f"{COS_API_URL}/templates/{template_id}/execute",
            json={
                "variables": variables,
                "platform": platform,
            }
        )

        if response.status_code == 404:
            return {"error": f"Template not found: {template_id}"}

        if response.status_code != 200:
            return {"error": f"Template execution failed: {response.text}"}

        return response.json()


@mcp.tool
async def chat(
    message: str,
    conversation_id: str | None = None,
) -> dict:
    """
    Have a conversation with the COS analysis agent.

    The agent can help you:
    - Analyze content interactively
    - Get recommendations for improvement
    - Understand framework scores
    - Configure analysis settings

    Args:
        message: Your message to the COS agent
        conversation_id: Optional ID to continue an existing conversation

    Returns:
        Agent response with analysis, suggestions, and conversation context
    """
    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.post(
            f"{COS_API_URL}/chat/",
            json={
                "messages": [{"role": "user", "content": message}],
                "conversation_id": conversation_id,
            }
        )

        if response.status_code != 200:
            return {"error": f"Chat failed: {response.text}"}

        return response.json()


@mcp.tool
async def get_template_details(template_id: str) -> dict:
    """
    Get detailed information about a specific template.

    Returns the template's:
    - Name and description
    - Required and optional variables with types
    - Categories and tags
    - Scoring dimensions and weights

    Args:
        template_id: The template ID to get details for

    Returns:
        Full template specification including variables and scoring config
    """
    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.get(f"{COS_API_URL}/templates/{template_id}")

        if response.status_code == 404:
            return {"error": f"Template not found: {template_id}"}

        if response.status_code != 200:
            return {"error": f"Failed to fetch template: {response.text}"}

        return response.json()


# Extended Analyzers (Persuasion, Platform, Quality)

DomainType = Literal["business", "politics", "health", "masculinity", "comedy"]


@mcp.tool
async def analyze_persuasion(
    content: str,
    domain: DomainType = "business",
    platform: PlatformType = "general",
    target_audience: str | None = None,
) -> dict:
    """
    Analyze content using domain-specific persuasion frameworks.

    Each domain has specialized scoring dimensions:
    - business: B2B/B2C messaging, ROI framing, objection handling
    - politics: Political messaging, polarization awareness, coalition building
    - health: Medical accuracy, safety messaging, behavior change (CRITICAL domain)
    - masculinity: Identity messaging, status signaling, tribe alignment
    - comedy: Humor mechanics, timing, callback patterns

    Args:
        content: The text content to analyze (min 50 characters)
        domain: The domain context for persuasion analysis
        platform: Target platform for optimization
        target_audience: Description of intended audience

    Returns:
        Domain-specific persuasion analysis with strengths, warnings, and recommendations
    """
    if len(content) < 50:
        return {"error": "Content must be at least 50 characters for meaningful analysis"}

    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.post(
            f"{COS_API_URL}/analyze/persuasion/{domain}",
            json={
                "content": content,
                "platform": platform,
                "target_audience": target_audience,
            }
        )

        if response.status_code != 200:
            return {"error": f"Persuasion analysis failed: {response.text}"}

        return response.json()


@mcp.tool
async def analyze_platform(
    content: str,
    platform: PlatformType = "linkedin",
    target_audience: str | None = None,
) -> dict:
    """
    Analyze content for platform-specific optimization.

    Evaluates content against platform constraints and algorithm preferences:
    - Character limits and formatting rules
    - Algorithm optimization signals
    - Engagement pattern recommendations
    - Platform-specific best practices

    Supported platforms: twitter, linkedin, email, youtube, tiktok, instagram,
    facebook, medium, substack, podcast, newsletter, slack, discord

    Args:
        content: The text content to analyze (min 50 characters)
        platform: The target platform for optimization
        target_audience: Description of intended audience

    Returns:
        Platform analysis with constraint checks, violations, and algorithm tips
    """
    if len(content) < 50:
        return {"error": "Content must be at least 50 characters for meaningful analysis"}

    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.post(
            f"{COS_API_URL}/analyze/platform/{platform}",
            json={
                "content": content,
                "platform": platform,
                "target_audience": target_audience,
            }
        )

        if response.status_code != 200:
            return {"error": f"Platform analysis failed: {response.text}"}

        return response.json()


@mcp.tool
async def analyze_quality(
    content: str,
    platform: PlatformType = "general",
    target_audience: str | None = None,
) -> dict:
    """
    Analyze content quality across 5 dimensions.

    Quality dimensions evaluated:
    - Clarity: Is the message easy to understand?
    - Coherence: Does the content flow logically?
    - Correctness: Grammar, spelling, factual accuracy
    - Completeness: Are all necessary elements present?
    - Conciseness: Is the content appropriately tight?

    Args:
        content: The text content to analyze (min 50 characters)
        platform: Target platform context
        target_audience: Description of intended audience

    Returns:
        Quality scores across 5 dimensions with specific improvement suggestions
    """
    if len(content) < 50:
        return {"error": "Content must be at least 50 characters for meaningful analysis"}

    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.post(
            f"{COS_API_URL}/analyze/quality",
            json={
                "content": content,
                "platform": platform,
                "target_audience": target_audience,
            }
        )

        if response.status_code != 200:
            return {"error": f"Quality analysis failed: {response.text}"}

        return response.json()


@mcp.tool
async def analyze_full_comms(
    content: str,
    domain: DomainType = "business",
    platform: PlatformType = "linkedin",
    target_audience: str | None = None,
) -> dict:
    """
    Run all 7 COS frameworks in parallel for comprehensive analysis.

    This is the most thorough analysis option, running:
    - Core 4: HAPE, Big Five, Strategic Clarity, Framing Strategy
    - Extended 3: Persuasion (domain-specific), Platform, Quality

    Use this when you need complete analysis across all dimensions.
    Takes longer but provides the most comprehensive view.

    Args:
        content: The text content to analyze (min 50 characters)
        domain: Domain for persuasion analysis
        platform: Target platform for optimization
        target_audience: Description of intended audience

    Returns:
        Complete analysis results from all 7 frameworks
    """
    if len(content) < 50:
        return {"error": "Content must be at least 50 characters for meaningful analysis"}

    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.post(
            f"{COS_API_URL}/analyze/full-comms",
            json={
                "content": content,
                "domain": domain,
                "platform": platform,
                "target_audience": target_audience,
            }
        )

        if response.status_code != 200:
            return {"error": f"Full comms analysis failed: {response.text}"}

        return response.json()


@mcp.tool
async def profile_agent(
    samples: list[str],
    agent_name: str = "Unknown Agent",
) -> dict:
    """
    Profile an agent's personality from their writing samples.

    Analyzes 1-10 writing samples (3-5 recommended) to infer the author's
    Big Five (OCEAN) personality traits, communication style, strengths,
    blind spots, and persuasion profile.

    This is the inverse of content analysis -- instead of "is this content effective?",
    it answers "who is this writer based on how they communicate?"

    Args:
        samples: List of writing samples from the agent (min 50 chars each, 3-5 recommended)
        agent_name: Name of the agent being profiled

    Returns:
        Agent profile with OCEAN traits (0.0-1.0), style label, strengths,
        blind spots, persuasion profile, and overall communication score
    """
    if not samples:
        return {"error": "At least one writing sample is required"}

    for i, sample in enumerate(samples):
        if len(sample) < 50:
            return {"error": f"Sample {i + 1} must be at least 50 characters"}

    async with httpx.AsyncClient(headers=_get_headers(), timeout=TIMEOUT) as client:
        response = await client.post(
            f"{COS_API_URL}/analyze/profile",
            json={
                "samples": samples,
                "agent_name": agent_name,
            }
        )

        if response.status_code != 200:
            return {"error": f"Agent profiling failed: {response.text}"}

        return response.json()


def main():
    """Entry point for cos-mcp console script."""
    mcp.run()


if __name__ == "__main__":
    main()
