#!/usr/bin/env python3
"""
Marketing Tools MCP Server

A production-ready Model Context Protocol server providing 4 marketing tools
for AI assistants. Includes SEO analysis, schema markup generation, content
scoring, and internal linking strategy suggestions.

Author: Marketing Enigma AI
License: MIT
"""

import re
import json
from typing import Any
from mcp.server.fastmcp import FastMCP

# Initialize the MCP server
mcp = FastMCP("marketing-tools", "1.0.0")


# =============================================================================
# TOOL 1: Analyze SEO Meta Tags
# =============================================================================

@mcp.tool()
def analyze_seo_meta(
    url: str,
    meta_title: str = "",
    meta_description: str = ""
) -> dict[str, Any]:
    """
    Analyze SEO meta tags for a URL.

    Provides actionable feedback on meta title and description length,
    heading structure recommendations, and optimization suggestions.

    Args:
        url: The page URL to analyze
        meta_title: The page's meta title tag (optional for analysis)
        meta_description: The page's meta description tag (optional)

    Returns:
        Dictionary with analysis results and recommendations
    """
    results = {
        "url": url,
        "meta_title": {
            "value": meta_title,
            "length": len(meta_title),
            "optimal_range": "50-60 characters",
            "status": "good",
            "feedback": []
        },
        "meta_description": {
            "value": meta_description,
            "length": len(meta_description),
            "optimal_range": "150-160 characters",
            "status": "good",
            "feedback": []
        },
        "heading_structure": {
            "recommendations": [
                "Use exactly one H1 tag per page",
                "Follow hierarchical order: H1 → H2 → H3",
                "Include target keyword in H1",
                "Use H2/H3 tags for content sections"
            ]
        },
        "summary": ""
    }

    # Analyze meta title
    title_len = len(meta_title)
    if title_len == 0:
        results["meta_title"]["status"] = "missing"
        results["meta_title"]["feedback"].append("Add a meta title tag to improve CTR")
    elif title_len < 30:
        results["meta_title"]["status"] = "too_short"
        results["meta_title"]["feedback"].append(f"Title is too short ({title_len}). Aim for 50-60 characters.")
    elif title_len < 50:
        results["meta_title"]["status"] = "acceptable"
        results["meta_title"]["feedback"].append("Expand title to 50-60 characters for better visibility")
    elif title_len <= 60:
        results["meta_title"]["status"] = "optimal"
        results["meta_title"]["feedback"].append("Title length is optimal for search results")
    else:
        results["meta_title"]["status"] = "too_long"
        results["meta_title"]["feedback"].append(f"Title is too long ({title_len}). Truncate to under 60 characters.")

    # Analyze meta description
    desc_len = len(meta_description)
    if desc_len == 0:
        results["meta_description"]["status"] = "missing"
        results["meta_description"]["feedback"].append("Add a meta description to improve CTR and SERP appearance")
    elif desc_len < 120:
        results["meta_description"]["status"] = "too_short"
        results["meta_description"]["feedback"].append(f"Description is too short ({desc_len}). Aim for 150-160 characters.")
    elif desc_len < 150:
        results["meta_description"]["status"] = "acceptable"
        results["meta_description"]["feedback"].append("Expand description to 150-160 characters")
    elif desc_len <= 160:
        results["meta_description"]["status"] = "optimal"
        results["meta_description"]["feedback"].append("Description length is optimal")
    else:
        results["meta_description"]["status"] = "too_long"
        results["meta_description"]["feedback"].append(f"Description is too long ({desc_len}). Aim for under 160 characters.")

    # Generate summary
    summary_parts = []
    if results["meta_title"]["status"] != "optimal":
        summary_parts.append("meta title needs optimization")
    if results["meta_description"]["status"] != "optimal":
        summary_parts.append("meta description needs optimization")
    if not summary_parts:
        results["summary"] = "All meta tags are optimized"
    else:
        results["summary"] = "; ".join(summary_parts).capitalize()

    return results


# =============================================================================
# TOOL 2: Generate Schema Markup
# =============================================================================

@mcp.tool()
def generate_schema_markup(
    page_type: str,
    title: str,
    description: str = "",
    author: str = "",
    date_published: str = "",
    image_url: str = ""
) -> dict[str, Any]:
    """
    Generate JSON-LD schema markup for a page.

    Supports article, FAQ, how-to, and product schema types.

    Args:
        page_type: Type of page (article, faq, howto, product)
        title: Page or product title
        description: Page or product description
        author: Content author name (for articles)
        date_published: Publication date (ISO 8601 format)
        image_url: Featured image or product image URL

    Returns:
        Dictionary with JSON-LD schema markup and implementation info
    """

    # Validate page_type
    valid_types = {"article", "faq", "howto", "product"}
    if page_type.lower() not in valid_types:
        return {
            "error": f"Invalid page_type. Must be one of: {', '.join(valid_types)}",
            "page_type": page_type
        }

    page_type = page_type.lower()
    schema = {
        "@context": "https://schema.org",
        "@type": "",
        "name": title,
        "description": description
    }

    if page_type == "article":
        schema["@type"] = "NewsArticle"
        if author:
            schema["author"] = {
                "@type": "Person",
                "name": author
            }
        if date_published:
            schema["datePublished"] = date_published
        if image_url:
            schema["image"] = image_url

    elif page_type == "faq":
        schema["@type"] = "FAQPage"
        schema["mainEntity"] = [
            {
                "@type": "Question",
                "name": "Replace with your question",
                "acceptedAnswer": {
                    "@type": "Answer",
                    "text": "Replace with your answer"
                }
            }
        ]

    elif page_type == "howto":
        schema["@type"] = "HowTo"
        if image_url:
            schema["image"] = image_url
        schema["step"] = [
            {
                "@type": "HowToStep",
                "name": "Step 1",
                "text": "Replace with step instructions"
            }
        ]

    elif page_type == "product":
        schema["@type"] = "Product"
        if image_url:
            schema["image"] = image_url
        schema["offers"] = {
            "@type": "Offer",
            "priceCurrency": "USD",
            "price": "0.00",
            "availability": "https://schema.org/InStock"
        }
        schema["aggregateRating"] = {
            "@type": "AggregateRating",
            "ratingValue": "4.5",
            "reviewCount": "100"
        }

    return {
        "page_type": page_type,
        "schema_markup": schema,
        "html_implementation": f'<script type="application/ld+json">\n{json.dumps(schema, indent=2)}\n</script>',
        "notes": [
            "Add this script tag in your page <head>",
            "Replace placeholder values with actual data",
            "Test with Google's Rich Results Test: https://search.google.com/test/rich-results"
        ]
    }


# =============================================================================
# TOOL 3: Calculate Content Score
# =============================================================================

@mcp.tool()
def calculate_content_score(
    content: str,
    target_keyword: str = ""
) -> dict[str, Any]:
    """
    Calculate readability and SEO metrics for content.

    Analyzes word count, reading time, keyword density, and provides
    recommendations for improvement.

    Args:
        content: The text content to analyze
        target_keyword: Primary keyword to track density (optional)

    Returns:
        Dictionary with content metrics and recommendations
    """

    if not content or len(content.strip()) == 0:
        return {
            "error": "Content cannot be empty",
            "content_length": 0
        }

    # Basic metrics
    words = content.split()
    word_count = len(words)
    sentence_count = len(re.split(r'[.!?]+', content)) - 1
    paragraph_count = len(re.split(r'\n\n+', content))

    # Calculate reading time (average 200 words per minute)
    reading_time_minutes = max(1, round(word_count / 200))

    # Calculate average metrics
    avg_words_per_sentence = word_count / max(sentence_count, 1)
    avg_words_per_paragraph = word_count / max(paragraph_count, 1)

    # Keyword density
    keyword_density = 0
    keyword_occurrences = 0
    if target_keyword:
        keyword_lower = target_keyword.lower()
        keyword_occurrences = len(re.findall(
            rf'\b{re.escape(keyword_lower)}\b',
            content.lower()
        ))
        keyword_density = round((keyword_occurrences / word_count) * 100, 2)

    # Flesch Reading Ease score (simplified)
    # Formula: 206.835 - 1.015(words/sentences) - 84.6(syllables/words)
    # Using approximation: assuming avg 1.5 syllables per word
    flesch_score = max(0, min(100, 206.835 - (1.015 * avg_words_per_sentence) - (84.6 * 1.5)))

    if flesch_score >= 90:
        readability = "Very Easy (5th grade)"
    elif flesch_score >= 80:
        readability = "Easy (6th grade)"
    elif flesch_score >= 70:
        readability = "Fairly Easy (7th grade)"
    elif flesch_score >= 60:
        readability = "Standard (8th-9th grade)"
    elif flesch_score >= 50:
        readability = "Fairly Difficult (10th-12th grade)"
    elif flesch_score >= 30:
        readability = "Difficult (College)"
    else:
        readability = "Very Difficult (College graduate)"

    results = {
        "word_count": word_count,
        "sentence_count": sentence_count,
        "paragraph_count": paragraph_count,
        "reading_time_minutes": reading_time_minutes,
        "readability": {
            "flesch_score": round(flesch_score, 2),
            "level": readability,
            "avg_words_per_sentence": round(avg_words_per_sentence, 2)
        },
        "recommendations": []
    }

    # Content length recommendations
    if word_count < 300:
        results["recommendations"].append("Content is too short. Aim for 300+ words for better SEO")
    elif word_count < 1000:
        results["recommendations"].append("Good starting length. Consider 1000+ words for comprehensive coverage")
    elif word_count > 3000:
        results["recommendations"].append("Content is lengthy. Consider breaking into multiple posts or using subheadings")
    else:
        results["recommendations"].append("Content length is optimal (300-3000 words)")

    # Readability recommendations
    if flesch_score < 60:
        results["recommendations"].append("Reduce sentence length. Use shorter, simpler sentences")
        results["recommendations"].append("Break paragraphs into smaller chunks")
    elif flesch_score > 90:
        results["recommendations"].append("Content is very simple. Consider adding more depth for authority")

    # Keyword density
    if target_keyword:
        results["keyword_analysis"] = {
            "keyword": target_keyword,
            "occurrences": keyword_occurrences,
            "density_percent": keyword_density,
            "recommendation": ""
        }

        if keyword_density == 0:
            results["keyword_analysis"]["recommendation"] = "Keyword not found. Naturally incorporate it 2-3 times."
        elif keyword_density < 0.5:
            results["keyword_analysis"]["recommendation"] = "Keyword density is low. Add keyword naturally 1-2 more times."
        elif keyword_density <= 2:
            results["keyword_analysis"]["recommendation"] = "Keyword density is optimal (0.5-2%)"
        elif keyword_density <= 3:
            results["keyword_analysis"]["recommendation"] = "Keyword density is slightly high. Avoid over-optimization."
        else:
            results["keyword_analysis"]["recommendation"] = "Keyword density is too high (>3%). Risk of keyword stuffing."

        results["recommendations"].append(results["keyword_analysis"]["recommendation"])

    # General improvements
    results["recommendations"].append("Use subheadings (H2/H3) to break up content")
    results["recommendations"].append("Add bullet points or numbered lists for scannability")
    results["recommendations"].append("Include internal links to related content")

    results["score"] = {
        "overall": round((word_count / 1000 + flesch_score / 100) / 2 * 50, 1),
        "max": 100,
        "components": {
            "length_score": min(100, (word_count / 1000) * 50),
            "readability_score": flesch_score,
            "keyword_score": min(100, (2 / max(keyword_density, 0.1))) if target_keyword else 100
        }
    }

    return results


# =============================================================================
# TOOL 4: Suggest Internal Links
# =============================================================================

@mcp.tool()
def suggest_internal_links(
    page_topic: str,
    existing_pages: list[str],
    link_count: int = 5
) -> dict[str, Any]:
    """
    Suggest internal linking strategy for a page.

    Analyzes page topic and compares against existing content to recommend
    contextual internal links that improve SEO and user experience.

    Args:
        page_topic: The main topic/title of the page being optimized
        existing_pages: List of other page titles in your site
        link_count: Number of internal links to suggest (default 5, max 10)

    Returns:
        Dictionary with internal linking strategy and recommendations
    """

    if link_count > 10:
        link_count = 10
    if link_count < 1:
        link_count = 1

    if not existing_pages:
        return {
            "error": "No existing pages provided. Need at least 2 pages for linking strategy.",
            "page_topic": page_topic
        }

    # Normalize inputs
    topic_words = set(page_topic.lower().split())

    # Score each page for relevance
    scored_pages = []
    for page in existing_pages:
        page_words = set(page.lower().split())

        # Calculate word overlap (Jaccard similarity)
        intersection = len(topic_words & page_words)
        union = len(topic_words | page_words)
        similarity = intersection / union if union > 0 else 0

        # Don't link to the same page
        if page.lower() == page_topic.lower():
            similarity = 0

        if similarity > 0:
            scored_pages.append({
                "page": page,
                "similarity_score": round(similarity * 100, 2),
                "matching_keywords": list(topic_words & page_words)
            })

    # Sort by relevance and get top N
    scored_pages.sort(key=lambda x: x["similarity_score"], reverse=True)
    suggested_links = scored_pages[:link_count]

    # If not enough relevant pages, add some with lower relevance
    if len(suggested_links) < link_count and len(scored_pages) > link_count:
        suggested_links.extend(scored_pages[link_count:min(link_count + 3, len(scored_pages))])

    # Categorize links
    contextual_links = [l for l in suggested_links if l["similarity_score"] >= 20]
    navigation_links = suggested_links[len(contextual_links):]

    return {
        "page_topic": page_topic,
        "total_existing_pages": len(existing_pages),
        "linking_strategy": {
            "contextual_links": {
                "count": len(contextual_links),
                "purpose": "These pages share related topics with your current page",
                "links": contextual_links[:5]
            },
            "navigation_links": {
                "count": len(navigation_links),
                "purpose": "These pages provide additional context or support",
                "links": navigation_links[:5]
            }
        },
        "best_practices": [
            "Use descriptive anchor text with 2-4 words",
            "Link to pages with similar content relevance (20%+ similarity minimum)",
            "Aim for 3-5 internal links per page (avoid over-linking)",
            "Link in the main content area, not just footer/sidebar",
            "Use natural language in links (avoid 'click here')",
            "Ensure linked pages are publicly indexed and active",
            "Prioritize links to pages that rank for related keywords"
        ],
        "summary": f"Found {len(suggested_links)} relevant pages to link to. {len(contextual_links)} are highly contextual."
    }


# =============================================================================
# Server Entry Point
# =============================================================================

if __name__ == "__main__":
    mcp.run()
