"""
================================================================================
MCP SERVER FOR MEGPT AUTHOR CONTENT
================================================================================

PURPOSE:
This script creates and runs a Model Context Protocol (MCP) server that serves
any meGPT author's content from generated MCP JSON resources. The server provides
tools, resources, and prompts for AI applications to interact with the content
collection through the standardized MCP interface.

ARCHITECTURE:
- Tools: AI-callable functions for content search, filtering, and analytics
- Resources: Direct data access endpoints for browsing content collections
- Prompts: Pre-built templates for common content analysis tasks
- Transport: Supports STDIO (Claude Desktop), HTTP (web apps), and SSE (legacy)

FUNCTIONALITY:
- Loads MCP JSON resources generated by create_mcp.py for any author
- Provides semantic search across titles, tags, and sources
- Enables content filtering by type, tags, and metadata
- Supports exact ID lookups and fuzzy content discovery
- Generates collection statistics and analytics
- Offers intelligent prompts for content analysis scenarios
- Handles multiple authors through command-line configuration

CONTENT TYPES SUPPORTED:
- YouTube videos: Individual videos, playlists, and entire channels
- Podcasts: Episodes with transcripts and summaries
- Books: PDFs with extracted text and summaries
- Stories: Narrative content with optional PDF attachments
- Files: Blog archives (Medium, Blogger), presentations, documents
- InfoQ videos: Technical conference presentations

ENHANCED FEATURES:
- File kind processing: Automatically processes directory-based content
- Blog archive support: Medium and Blogger post collections
- YouTube channel processing: Extracts all videos from channels
- PDF handling: Preprocessed text extraction and summary generation
- URL standardization: Converts relative paths to full GitHub URLs
- Content deduplication: Prevents duplicate processing by URL matching
- Cache management: Excludes internal cache files from content listings

INTEGRATION CAPABILITIES:
- Claude Desktop: Direct integration for content-aware conversations
- Cursor/Windsurf: Enhanced coding assistance with domain knowledge
- Custom AI Agents: LangGraph, OpenAI SDK, Firebase Genkit workflows
- Personal AI Assistants: Content-aware chatbots and research tools

CURRENT CONTENT STATISTICS (virtual_adrianco):
- Total items: 611 content pieces
- YouTube videos: 135 (including channels, playlists, individual videos)
- File archives: 394 (Medium posts, Blogger posts, presentations)
- Podcast episodes: 52 (with transcripts and summaries)
- Stories: 18 (narrative content)
- Books: 10 (PDFs with extracted text)
- InfoQ videos: 2 (technical presentations)

DEPENDENCIES:
- fastmcp: Simplified MCP server framework with automatic JSON-RPC handling
- Standard libraries: json, pathlib, dataclasses, argparse, typing

USAGE:
    python mcp_server.py [--author AUTHOR] [--transport TRANSPORT] [--port PORT] [--host HOST]
    
    Arguments:
        --author: Author name for content (default: virtual_adrianco)
        --transport: Transport type: stdio, streamable-http, or sse (default: stdio)
        --port: Port to run server on for HTTP transports (default: 8000)
        --host: Host to run the server on for HTTP transports (default: 127.0.0.1)
    
    Examples:
        python mcp_server.py                                    # Default STDIO mode
        python mcp_server.py --transport streamable-http --port 8080  # HTTP mode

IMPORTANT CONSIDERATIONS:
- Server must load valid MCP JSON resources before starting
- Content search is performed in-memory for fast response times
- All responses are JSON-formatted for MCP client compatibility
- Error handling ensures graceful degradation for missing content
- Resource URIs follow content:// scheme for standardized access
- Follows MCP specification for tools, resources, and prompts

DEVELOPMENT CONTEXT:
This server was developed to demonstrate MCP capabilities with real content data.
It transforms the meGPT content collection into an AI-accessible knowledge base
that enhances conversations, provides context-aware assistance, and enables
content discovery across various AI applications and frameworks. The server
has been enhanced to support comprehensive file processing, YouTube channel
extraction, and blog archive integration, making it a robust content platform
for AI-powered applications.
================================================================================
"""

import json
import os
import sys
import asyncio
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
import re
from dataclasses import dataclass, asdict
import argparse

from fastmcp import FastMCP

# Content data structure
@dataclass
class ContentItem:
    id: str
    kind: str
    subkind: str
    title: str
    source: str
    published_date: str
    url: str
    content: Dict[str, Any]
    tags: List[str]
    summary: Optional[str] = None
    word_count: Optional[int] = None

class ContentMCPServer:
    def __init__(self, author: str = "virtual_adrianco"):
        self.author = author
        self.mcp = FastMCP(f"meGPT Content Server ({author})")
        self.content_data: Dict[str, Any] = {}
        self.content_items: List[ContentItem] = []
        
        # Load content data
        self._load_content()
        
        # Setup MCP handlers
        self._setup_tools()
        self._setup_resources()
        self._setup_prompts()
        
    def _load_content(self):
        """Load content from MCP JSON file"""
        mcp_file = Path(f"mcp_resources/{self.author}/mcp_resource.json")
        
        if not mcp_file.exists():
            print(f"Error: MCP resource file not found at {mcp_file}")
            print("Please run create_mcp.py first to generate the MCP resource.")
            sys.exit(1)
            
        try:
            with open(mcp_file, 'r', encoding='utf-8') as f:
                self.content_data = json.load(f)
                
            # Convert content items to ContentItem objects
            for item_data in self.content_data.get('content', []):
                item = ContentItem(
                    id=item_data.get('id', ''),
                    kind=item_data.get('kind', ''),
                    subkind=item_data.get('subkind', ''),
                    title=item_data.get('title', ''),
                    source=item_data.get('source', ''),
                    published_date=item_data.get('published_date', ''),
                    url=item_data.get('url', ''),
                    content=item_data.get('content', {}),
                    tags=item_data.get('tags', []),
                    summary=item_data.get('summary'),
                    word_count=item_data.get('word_count')
                )
                self.content_items.append(item)
                
            print(f"Loaded {len(self.content_items)} content items for {self.author}")
            
        except Exception as e:
            print(f"Error loading content data: {e}")
            sys.exit(1)
    
    def _setup_tools(self):
        """Setup MCP tools for content interaction"""
        
        @self.mcp.tool()
        def search_content(query: str, content_type: Optional[str] = None, limit: int = 10) -> str:
            """
            Search through the author's content by title, tags, or source.
            
            Args:
                query: Search term to look for in titles, tags, and sources
                content_type: Optional filter by content type (podcast, youtube, book, etc.)
                limit: Maximum number of results to return (default 10)
            """
            query_lower = query.lower()
            results = []
            
            for item in self.content_items:
                # Skip if content type filter doesn't match
                if content_type and item.kind != content_type:
                    continue
                    
                # Search in title, tags, and source
                matches = (
                    query_lower in item.title.lower() or
                    query_lower in item.source.lower() or
                    any(query_lower in tag.lower() for tag in item.tags)
                )
                
                if matches:
                    result = {
                        "id": item.id,
                        "title": item.title,
                        "kind": item.kind,
                        "source": item.source,
                        "published_date": item.published_date,
                        "url": item.url,
                        "tags": item.tags,
                        "summary": item.summary
                    }
                    results.append(result)
                    
                if len(results) >= limit:
                    break
            
            return json.dumps({
                "query": query,
                "content_type_filter": content_type,
                "total_results": len(results),
                "results": results
            }, indent=2)
        
        @self.mcp.tool()
        def get_content_by_id(content_id: str) -> str:
            """
            Get detailed information about a specific content item by ID.
            
            Args:
                content_id: The unique ID of the content item
            """
            item = next((item for item in self.content_items if item.id == content_id), None)
            
            if not item:
                return json.dumps({"error": f"Content item with ID '{content_id}' not found"})
            
            return json.dumps(asdict(item), indent=2)
        
        @self.mcp.tool()
        def get_content_by_type(content_type: str, limit: int = 20) -> str:
            """
            Get all content items of a specific type.
            
            Args:
                content_type: Type of content (podcast, youtube, book, story, etc.)
                limit: Maximum number of items to return (default 20)
            """
            items = [item for item in self.content_items if item.kind == content_type][:limit]
            
            results = []
            for item in items:
                result = {
                    "id": item.id,
                    "title": item.title,
                    "source": item.source,
                    "published_date": item.published_date,
                    "url": item.url,
                    "tags": item.tags,
                    "summary": item.summary
                }
                results.append(result)
            
            return json.dumps({
                "content_type": content_type,
                "total_items": len(items),
                "showing": len(results),
                "items": results
            }, indent=2)
        
        @self.mcp.tool()
        def get_content_by_tags(tags: str, match_all: bool = False, limit: int = 15) -> str:
            """
            Find content items that have specific tags.
            
            Args:
                tags: Comma-separated list of tags to search for
                match_all: If True, content must have ALL tags. If False, content needs ANY tag (default)
                limit: Maximum number of results to return (default 15)
            """
            search_tags = [tag.strip().lower() for tag in tags.split(',')]
            results = []
            
            for item in self.content_items:
                item_tags_lower = [tag.lower() for tag in item.tags]
                
                if match_all:
                    # Must have all tags
                    has_tags = all(tag in item_tags_lower for tag in search_tags)
                else:
                    # Must have at least one tag
                    has_tags = any(tag in item_tags_lower for tag in search_tags)
                
                if has_tags:
                    result = {
                        "id": item.id,
                        "title": item.title,
                        "kind": item.kind,
                        "source": item.source,
                        "published_date": item.published_date,
                        "url": item.url,
                        "tags": item.tags,
                        "summary": item.summary
                    }
                    results.append(result)
                    
                if len(results) >= limit:
                    break
            
            return json.dumps({
                "search_tags": search_tags,
                "match_all": match_all,
                "total_results": len(results),
                "results": results
            }, indent=2)
        
        @self.mcp.tool()
        def get_content_statistics() -> str:
            """Get statistics about the author's content collection."""
            metadata = self.content_data.get('metadata', {})
            
            # Calculate additional stats
            total_with_tags = sum(1 for item in self.content_items if item.tags)
            total_with_summaries = sum(1 for item in self.content_items if item.summary)
            
            # Get all unique tags
            all_tags = set()
            for item in self.content_items:
                all_tags.update(item.tags)
            
            # Get sources
            sources = {}
            for item in self.content_items:
                sources[item.source] = sources.get(item.source, 0) + 1
            
            stats = {
                "metadata": metadata,
                "content_analysis": {
                    "total_items": len(self.content_items),
                    "items_with_tags": total_with_tags,
                    "items_with_summaries": total_with_summaries,
                    "unique_tags_count": len(all_tags),
                    "unique_sources_count": len(sources),
                    "top_sources": dict(sorted(sources.items(), key=lambda x: x[1], reverse=True)[:10])
                },
                "all_tags": sorted(list(all_tags)),
                "content_types": metadata.get('content_types', {})
            }
            
            return json.dumps(stats, indent=2)
    
    def _setup_resources(self):
        """Setup MCP resources for content access"""
        
        @self.mcp.resource("content://metadata")
        def get_metadata() -> str:
            """Get metadata about the author's content collection"""
            return json.dumps(self.content_data.get('metadata', {}), indent=2)
        
        @self.mcp.resource("content://all")
        def get_all_content() -> str:
            """Get all content items (summary view)"""
            summary_items = []
            for item in self.content_items:
                summary = {
                    "id": item.id,
                    "title": item.title,
                    "kind": item.kind,
                    "source": item.source,
                    "published_date": item.published_date,
                    "url": item.url,
                    "tags": item.tags
                }
                summary_items.append(summary)
            
            return json.dumps({
                "total_items": len(summary_items),
                "items": summary_items
            }, indent=2)
        
        @self.mcp.resource("content://types")
        def get_content_types() -> str:
            """Get all available content types and their counts"""
            return json.dumps(self.content_data.get('metadata', {}).get('content_types', {}), indent=2)
        
        @self.mcp.resource("content://tags")
        def get_all_tags() -> str:
            """Get all unique tags used in the content"""
            all_tags = set()
            tag_counts = {}
            
            for item in self.content_items:
                for tag in item.tags:
                    all_tags.add(tag)
                    tag_counts[tag] = tag_counts.get(tag, 0) + 1
            
            return json.dumps({
                "total_unique_tags": len(all_tags),
                "tags": sorted(list(all_tags)),
                "tag_usage_counts": dict(sorted(tag_counts.items(), key=lambda x: x[1], reverse=True))
            }, indent=2)
    
    def _setup_prompts(self):
        """Setup MCP prompts for common content interactions"""
        
        @self.mcp.prompt()
        def analyze_content_topic(topic: str) -> str:
            """
            Analyze the author's content related to a specific topic.
            
            Args:
                topic: The topic to analyze (e.g., "microservices", "Netflix", "cloud")
            """
            return f"""Please analyze this author's content related to "{topic}". 

First, search for content using the search_content tool with the query "{topic}".

Then provide an analysis that includes:
1. Overview of how much content the author has on this topic
2. Key themes and insights from the content titles and summaries
3. Evolution of their thinking on this topic over time (if publication dates are available)
4. Different formats they've used to discuss this topic (podcasts, videos, books, etc.)
5. Related topics and tags that frequently appear with this content

Use the available tools to gather comprehensive information before providing your analysis."""

        @self.mcp.prompt()
        def content_recommendation(interest: str) -> str:
            """
            Get content recommendations based on interests.
            
            Args:
                interest: Area of interest (e.g., "platform engineering", "sustainability", "AI")
            """
            return f"""Please recommend this author's content for someone interested in "{interest}".

Use the search_content and get_content_by_tags tools to find relevant content.

Provide recommendations in this format:
1. **Top Recommendations**: 3-5 most relevant pieces of content with brief explanations of why they're valuable
2. **Content by Format**: Organize recommendations by type (podcasts for commuting, videos for visual learning, books for deep dives, etc.)
3. **Learning Path**: Suggest an order for consuming the content, from introductory to advanced
4. **Related Topics**: Other areas the author covers that might interest someone with this focus

Include titles, sources, URLs, and brief descriptions for each recommendation."""

        @self.mcp.prompt()
        def content_summary_report() -> str:
            """Generate a comprehensive summary report of the author's content collection."""
            return """Please generate a comprehensive summary report of this author's content collection.

Use the get_content_statistics tool to gather data, then create a report that includes:

1. **Collection Overview**
   - Total number of items and content types
   - Publication timeline and activity patterns
   - Most active sources and platforms

2. **Topic Analysis**
   - Most frequently discussed topics (based on tags)
   - Emerging themes and trends
   - Cross-format topic coverage

3. **Content Quality Metrics**
   - Items with summaries vs. those without
   - Tag coverage and organization
   - Content accessibility and discoverability

4. **Recommendations for Content Strategy**
   - Gaps in content coverage
   - Opportunities for content organization
   - Suggestions for improving discoverability

Format the report in a clear, structured manner with specific data points and actionable insights."""

def main():
    parser = argparse.ArgumentParser(description="meGPT Author Content MCP Server")
    parser.add_argument("--author", default="virtual_adrianco", 
                       help="Author name for content (default: virtual_adrianco)")
    parser.add_argument("--transport", default="stdio",
                       help="Transport type: stdio, streamable-http, or sse (default: stdio)")
    parser.add_argument("--port", type=int, default=8000,
                       help="Port to run the server on for HTTP transports (default: 8000)")
    parser.add_argument("--host", default="127.0.0.1",
                       help="Host to run the server on for HTTP transports (default: 127.0.0.1)")
    
    args = parser.parse_args()
    
    # Create and run the server
    server = ContentMCPServer(author=args.author)
    
    print(f"Starting meGPT Content MCP Server for author: {args.author}")
    print(f"Transport: {args.transport}")
    if args.transport in ["streamable-http", "sse"]:
        print(f"Server will be available at http://{args.host}:{args.port}")
    print(f"Loaded {len(server.content_items)} content items")
    print("\nAvailable tools:")
    print("- search_content: Search through content by query")
    print("- get_content_by_id: Get detailed content by ID")
    print("- get_content_by_type: Get all content of a specific type")
    print("- get_content_by_tags: Find content by tags")
    print("- get_content_statistics: Get collection statistics")
    print("\nAvailable resources:")
    print("- content://metadata: Collection metadata")
    print("- content://all: All content items")
    print("- content://types: Content types and counts")
    print("- content://tags: All tags and usage")
    print("\nAvailable prompts:")
    print("- analyze_content_topic: Analyze content on a topic")
    print("- content_recommendation: Get content recommendations")
    print("- content_summary_report: Generate summary report")
    
    # Run the server with appropriate transport
    if args.transport == "stdio":
        server.mcp.run()
    elif args.transport == "streamable-http":
        server.mcp.run(transport="streamable-http", host=args.host, port=args.port)
    elif args.transport == "sse":
        server.mcp.run(transport="sse", host=args.host, port=args.port)
    else:
        print(f"Error: Unknown transport '{args.transport}'. Use stdio, streamable-http, or sse.")
        sys.exit(1)

if __name__ == "__main__":
    main() 