#!/usr/bin/env python3
"""
Google Scholar MCP Server
Provides academic paper search and information retrieval using Google Scholar.
"""

import asyncio
import json
import logging
from typing import Any, Dict, List, Optional
import sys
import os
import random
import re

# Add the parent directory to the path to import mcp
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from mcp.server.models import InitializationOptions
from mcp.server import NotificationOptions, Server
from mcp.types import (
    Resource, 
    Tool, 
    TextContent, 
    ImageContent, 
    EmbeddedResource,
    LoggingLevel
)
import mcp.types as types

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("google-scholar-mcp")

# Global variable to store the server instance
server = Server("google-scholar-mcp")

try:
    import scholarly
    from scholarly import scholarly as sch_module
    SCHOLARLY_AVAILABLE = True
except ImportError:
    SCHOLARLY_AVAILABLE = False
    logger.warning("scholarly library not installed. Install with: pip install scholarly")

# Configurable polite delays to reduce blocking (jittered)
REQUEST_DELAY_MIN_SECONDS = float(os.getenv("SCHOLAR_DELAY_MIN", "2.0"))
REQUEST_DELAY_MAX_SECONDS = float(os.getenv("SCHOLAR_DELAY_MAX", "5.0"))
if REQUEST_DELAY_MAX_SECONDS < REQUEST_DELAY_MIN_SECONDS:
    REQUEST_DELAY_MAX_SECONDS = REQUEST_DELAY_MIN_SECONDS

async def _polite_delay() -> None:
    await asyncio.sleep(random.uniform(REQUEST_DELAY_MIN_SECONDS, REQUEST_DELAY_MAX_SECONDS))

# Detect provider and keys
PROVIDER = os.getenv("SCHOLAR_PROXY_PROVIDER", "").strip().lower()
SERPAPI_KEY = os.getenv("SERPAPI_KEY", "").strip()
SCRAPERAPI_KEY = os.getenv("SCRAPERAPI_KEY", "").strip()
USE_SERPAPI = PROVIDER == "serpapi" and bool(SERPAPI_KEY)

# Optional proxy configuration via scholarly.ProxyGenerator (for non-SerpAPI providers)
if SCHOLARLY_AVAILABLE and not USE_SERPAPI:
    try:
        from scholarly import ProxyGenerator  # type: ignore

        def _configure_scholarly_proxy() -> None:
            provider = PROVIDER
            if not provider:
                logger.info("No proxy configured for Google Scholar (SCHOLAR_PROXY_PROVIDER not set). Requests may be blocked.")
                return

            pg = ProxyGenerator()
            try:
                if provider in {"free", "free_proxies", "freeproxies"}:
                    ok = pg.FreeProxies()
                    if ok:
                        sch_module.use_proxy(pg)
                        logger.info("Using FreeProxies for Google Scholar requests.")
                    else:
                        logger.warning("Failed to initialize FreeProxies provider.")
                elif provider == "tor":
                    tor_mode = os.getenv("TOR_MODE", "internal").strip().lower()
                    if tor_mode == "external":
                        sock_port = int(os.getenv("TOR_SOCKS_PORT", "9050"))
                        ctrl_port = int(os.getenv("TOR_CONTROL_PORT", "9051"))
                        tor_password = os.getenv("TOR_PASSWORD")
                        ok = pg.Tor_External(tor_sockport=sock_port, tor_controlport=ctrl_port, tor_password=tor_password)
                    else:
                        tor_cmd = os.getenv("TOR_CMD", "tor")
                        ok = pg.Tor_Internal(tor_cmd=tor_cmd)
                    if ok:
                        sch_module.use_proxy(pg)
                        logger.info("Using Tor proxy for Google Scholar requests.")
                    else:
                        logger.warning("Failed to initialize Tor proxy.")
                elif provider == "scraperapi":
                    used_fallback = False
                    if hasattr(ProxyGenerator, "ScraperAPI") and SCRAPERAPI_KEY:
                        try:
                            ok = pg.ScraperAPI(SCRAPERAPI_KEY)
                        except Exception as e:
                            logger.warning(f"ProxyGenerator.ScraperAPI init error: {e}")
                            ok = False
                    else:
                        ok = False
                    if ok:
                        sch_module.use_proxy(pg)
                        logger.info("Using ScraperAPI provider via scholarly ProxyGenerator.")
                    else:
                        # Fallback: set HTTP(S)_PROXY to ScraperAPI proxy endpoint
                        if SCRAPERAPI_KEY:
                            proxy_url = f"http://scraperapi:{SCRAPERAPI_KEY}@proxy.scraperapi.com:8001"
                            os.environ["HTTP_PROXY"] = proxy_url
                            os.environ["HTTPS_PROXY"] = proxy_url
                            logger.info("Using ScraperAPI via HTTP(S)_PROXY fallback.")
                        else:
                            logger.warning("SCRAPERAPI_KEY not set; cannot configure ScraperAPI provider.")
                elif provider == "serpapi":
                    # SerpAPI handled natively (bypasses scholarly scraping)
                    logger.info("Using SerpAPI backend for Google Scholar queries.")
                else:
                    logger.warning(f"Unsupported or unavailable SCHOLAR_PROXY_PROVIDER: {provider}")
            except Exception as e:
                logger.warning(f"Proxy configuration failed: {e}")

        _configure_scholarly_proxy()
    except Exception as e:
        logger.warning(f"Proxy support not available or failed to initialize: {e}")

# --------------- SerpAPI native client (async) ----------------
async def _serpapi_get_json(params: Dict[str, Any]) -> Optional[Dict[str, Any]]:
    try:
        import httpx  # local import
    except Exception as e:
        logger.error(f"httpx not available for SerpAPI: {e}")
        return None

    params = {**params, "api_key": SERPAPI_KEY}
    url = "https://serpapi.com/search.json"
    try:
        async with httpx.AsyncClient(timeout=30) as client:
            resp = await client.get(url, params=params)
            if resp.status_code != 200:
                logger.warning(f"SerpAPI HTTP {resp.status_code}: {resp.text[:200]}")
                return None
            return resp.json()
    except Exception as e:
        logger.error(f"SerpAPI request error: {e}")
        return None

def _extract_year_from_summary(summary: str) -> Optional[int]:
    try:
        match = re.search(r"(19|20)\d{2}", summary)
        if match:
            return int(match.group(0))
    except Exception:
        pass
    return None

async def _serpapi_search_papers_impl(arguments: Dict[str, Any]) -> List[types.TextContent]:
    query = arguments.get("query", "")
    max_results = min(arguments.get("max_results", 10), 20)
    if not query:
        return [types.TextContent(type="text", text="Error: Query parameter is required")]

    params = {
        "engine": "google_scholar",
        "q": query,
        "hl": "en",
        # SerpAPI supports pagination via 'start'; we will fetch first page only here
    }

    data = await _serpapi_get_json(params)
    if not data:
        return [types.TextContent(type="text", text="Error: SerpAPI request failed")]

    results = data.get("organic_results", []) or []
    papers = []
    for item in results[:max_results]:
        title = item.get("title") or "N/A"
        link = item.get("link") or item.get("result_id") or "N/A"
        snippet = item.get("snippet") or "N/A"
        pub_info = (item.get("publication_info") or {}).get("summary") or ""
        year = _extract_year_from_summary(pub_info) or "N/A"
        venue = pub_info
        citations = 0
        inline_links = item.get("inline_links") or {}
        if inline_links.get("cited_by") and isinstance(inline_links["cited_by"], dict):
            citations = inline_links["cited_by"].get("total", 0) or 0

        paper_info = {
            "title": title,
            "authors": pub_info,
            "year": year,
            "venue": venue,
            "abstract": snippet,
            "citations": citations,
            "url": link,
        }
        papers.append(paper_info)

    if not papers:
        return [types.TextContent(type="text", text=f"No papers found for query: '{query}'")]

    result_text = f"Found {len(papers)} papers for query: '{query}'\n\n"
    for i, paper in enumerate(papers, 1):
        result_text += f"**{i}. {paper['title']}**\n"
        result_text += f"   Authors: {paper['authors']}\n"
        result_text += f"   Year: {paper['year']}\n"
        result_text += f"   Venue: {paper['venue']}\n"
        result_text += f"   Citations: {paper['citations']}\n"
        if paper['abstract'] != 'N/A':
            result_text += f"   Abstract: {paper['abstract']}\n"
        if paper['url'] != 'N/A':
            result_text += f"   URL: {paper['url']}\n"
        result_text += "\n"

    return [types.TextContent(type="text", text=result_text)]

async def _serpapi_search_author_impl(arguments: Dict[str, Any]) -> List[types.TextContent]:
    author_name = arguments.get("author_name", "")
    max_results = min(arguments.get("max_results", 5), 10)
    if not author_name:
        return [types.TextContent(type="text", text="Error: Author name is required")]

    params = {
        "engine": "google_scholar_profiles",
        "mauthors": author_name,
        "hl": "en",
    }
    data = await _serpapi_get_json(params)
    if not data:
        return [types.TextContent(type="text", text="Error: SerpAPI request failed")]

    profiles = data.get("profiles", []) or []
    authors = []
    for item in profiles[:max_results]:
        name = item.get("name", "N/A")
        affiliation = item.get("affiliations", "N/A")
        interests = item.get("interests", []) or []
        citedby = (item.get("cited_by", {}) or {}).get("value", 0)
        scholar_id = item.get("author_id", "")
        url = f"https://scholar.google.com/citations?user={scholar_id}" if scholar_id else "N/A"

        authors.append({
            "name": name,
            "affiliation": affiliation,
            "email": "N/A",
            "interests": interests,
            "citedby": citedby,
            "scholar_id": scholar_id,
            "url": url,
        })

    if not authors:
        return [types.TextContent(type="text", text=f"No authors found for: '{author_name}'")]

    result_text = f"Found {len(authors)} authors for: '{author_name}'\n\n"
    for i, author in enumerate(authors, 1):
        result_text += f"**{i}. {author['name']}**\n"
        result_text += f"   Affiliation: {author['affiliation']}\n"
        if author['email'] != 'N/A':
            result_text += f"   Email: {author['email']}\n"
        if author['interests']:
            if isinstance(author['interests'], list):
                result_text += f"   Research Interests: {', '.join(author['interests'])}\n"
            else:
                result_text += f"   Research Interests: {author['interests']}\n"
        result_text += f"   Total Citations: {author['citedby']}\n"
        if author['url'] != 'N/A':
            result_text += f"   Scholar Profile: {author['url']}\n"
        result_text += "\n"

    return [types.TextContent(type="text", text=result_text)]

async def _serpapi_get_paper_details_impl(arguments: Dict[str, Any]) -> List[types.TextContent]:
    title = arguments.get("title", "")
    author = arguments.get("author", "")
    if not title:
        return [types.TextContent(type="text", text="Error: Paper title is required")]

    q = f"\"{title}\""
    if author:
        q += f" author:\"{author}\""

    params = {"engine": "google_scholar", "q": q, "hl": "en"}
    data = await _serpapi_get_json(params)
    if not data:
        return [types.TextContent(type="text", text="Error: SerpAPI request failed")]

    results = data.get("organic_results", []) or []
    for item in results:
        paper_title = item.get("title", "")
        if title.lower() in paper_title.lower() or paper_title.lower() in title.lower():
            link = item.get("link") or "N/A"
            snippet = item.get("snippet") or "N/A"
            pub_info = (item.get("publication_info") or {}).get("summary") or ""
            year = _extract_year_from_summary(pub_info) or "N/A"
            citations = 0
            inline_links = item.get("inline_links") or {}
            if inline_links.get("cited_by") and isinstance(inline_links["cited_by"], dict):
                citations = inline_links["cited_by"].get("total", 0) or 0

            result_text = "**Paper Details**\n\n"
            result_text += f"**Title:** {paper_title}\n\n"
            result_text += f"**Authors:** {pub_info}\n\n"
            result_text += f"**Year:** {year}\n\n"
            result_text += f"**Venue:** {pub_info}\n\n"
            result_text += f"**Citations:** {citations}\n\n"
            if snippet != 'N/A':
                result_text += f"**Abstract:**\n{snippet}\n\n"
            if link != 'N/A':
                result_text += f"**URL:** {link}\n\n"
            return [types.TextContent(type="text", text=result_text)]

    return [types.TextContent(type="text", text=f"Paper not found: '{title}'")]

async def _serpapi_get_citation_info_impl(arguments: Dict[str, Any]) -> List[types.TextContent]:
    title = arguments.get("title", "")
    author = arguments.get("author", "")
    if not title:
        return [types.TextContent(type="text", text="Error: Paper title is required")]

    q = f"\"{title}\""
    if author:
        q += f" author:\"{author}\""

    params = {"engine": "google_scholar", "q": q, "hl": "en"}
    data = await _serpapi_get_json(params)
    if not data:
        return [types.TextContent(type="text", text="Error: SerpAPI request failed")]

    results = data.get("organic_results", []) or []
    for item in results:
        paper_title = item.get("title", "")
        if title.lower() in paper_title.lower() or paper_title.lower() in title.lower():
            inline_links = item.get("inline_links") or {}
            citations = 0
            if inline_links.get("cited_by") and isinstance(inline_links["cited_by"], dict):
                citations = inline_links["cited_by"].get("total", 0) or 0
            pub_info = (item.get("publication_info") or {}).get("summary") or ""
            year = _extract_year_from_summary(pub_info)

            current_year = 2024
            if year is not None:
                years_since_pub = max(current_year - year, 1)
                citations_per_year = citations / years_since_pub
            else:
                year = 'N/A'
                citations_per_year = 0

            result_text = f"**Citation Information for:** {paper_title}\n\n"
            result_text += f"**Total Citations:** {citations}\n"
            result_text += f"**Publication Year:** {year}\n"
            if year != 'N/A':
                result_text += f"**Citations per Year:** {citations_per_year:.1f}\n"

            if citations >= 1000:
                impact = "Very High Impact"
            elif citations >= 100:
                impact = "High Impact"
            elif citations >= 50:
                impact = "Moderate Impact"
            elif citations >= 10:
                impact = "Some Impact"
            else:
                impact = "Limited Impact"
            result_text += f"**Impact Assessment:** {impact}\n\n"
            return [types.TextContent(type="text", text=result_text)]

    return [types.TextContent(type="text", text=f"Paper not found for citation analysis: '{title}'")]

# -----------------------------------------------------------------
@server.list_tools()
async def handle_list_tools() -> List[Tool]:
    """List available Google Scholar tools."""
    tools = [
        Tool(
            name="search_papers",
            description="Search for academic papers on Google Scholar",
            inputSchema={
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Search query for academic papers"
                    },
                    "max_results": {
                        "type": "integer",
                        "description": "Maximum number of results to return (default: 10, max: 20)",
                        "default": 10,
                        "minimum": 1,
                        "maximum": 20
                    },
                    "year_low": {
                        "type": "integer",
                        "description": "Earliest publication year to include (optional)"
                    },
                    "year_high": {
                        "type": "integer",
                        "description": "Latest publication year to include (optional)"
                    }
                },
                "required": ["query"]
            }
        ),
        Tool(
            name="search_author",
            description="Search for authors and their publications on Google Scholar",
            inputSchema={
                "type": "object",
                "properties": {
                    "author_name": {
                        "type": "string",
                        "description": "Name of the author to search for"
                    },
                    "max_results": {
                        "type": "integer",
                        "description": "Maximum number of authors to return (default: 5, max: 10)",
                        "default": 5,
                        "minimum": 1,
                        "maximum": 10
                    }
                },
                "required": ["author_name"]
            }
        ),
        Tool(
            name="get_paper_details",
            description="Get detailed information about a specific paper",
            inputSchema={
                "type": "object",
                "properties": {
                    "title": {
                        "type": "string",
                        "description": "Title of the paper to get details for"
                    },
                    "author": {
                        "type": "string",
                        "description": "First author name (optional, helps with disambiguation)"
                    }
                },
                "required": ["title"]
            }
        ),
        Tool(
            name="get_citation_info",
            description="Get citation information and metrics for a paper",
            inputSchema={
                "type": "object",
                "properties": {
                    "title": {
                        "type": "string",
                        "description": "Title of the paper to get citation info for"
                    },
                    "author": {
                        "type": "string",
                        "description": "First author name (optional)"
                    }
                },
                "required": ["title"]
            }
        )
    ]
    
    return tools

@server.call_tool()
async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[types.TextContent | types.ImageContent | types.EmbeddedResource]:
    """Handle tool calls for Google Scholar operations."""
    
    if not SCHOLARLY_AVAILABLE and not USE_SERPAPI:
        return [types.TextContent(
            type="text",
            text="Error: scholarly library is not installed. Please install it with: pip install scholarly"
        )]
    
    try:
        if name == "search_papers":
            if USE_SERPAPI:
                return await _serpapi_search_papers_impl(arguments)
            return await search_papers(arguments)
        elif name == "search_author":
            if USE_SERPAPI:
                return await _serpapi_search_author_impl(arguments)
            return await search_author(arguments)
        elif name == "get_paper_details":
            if USE_SERPAPI:
                return await _serpapi_get_paper_details_impl(arguments)
            return await get_paper_details(arguments)
        elif name == "get_citation_info":
            if USE_SERPAPI:
                return await _serpapi_get_citation_info_impl(arguments)
            return await get_citation_info(arguments)
        else:
            return [types.TextContent(
                type="text",
                text=f"Unknown tool: {name}"
            )]
    except Exception as e:
        logger.error(f"Error in {name}: {str(e)}")
        return [types.TextContent(
            type="text",
            text=f"Error executing {name}: {str(e)}"
        )]

async def search_papers(arguments: Dict[str, Any]) -> List[types.TextContent]:
    """Search for academic papers on Google Scholar."""
    query = arguments.get("query", "")
    max_results = min(arguments.get("max_results", 10), 20)
    year_low = arguments.get("year_low")
    year_high = arguments.get("year_high")
    
    if not query:
        return [types.TextContent(
            type="text",
            text="Error: Query parameter is required"
        )]
    
    try:
        # Configure search parameters
        search_query = sch_module.search_pubs(query)
        
        if year_low or year_high:
            year_low = year_low or 1900
            year_high = year_high or 2030
            search_query = sch_module.search_pubs(query, year_low=year_low, year_high=year_high)
        
        papers = []
        count = 0

        await _polite_delay()
        
        for paper in search_query:
            if count >= max_results:
                break
                
            try:
                # Extract paper information
                title = paper.get('title', 'N/A')
                authors = paper.get('author', 'N/A')
                year = paper.get('year', 'N/A')
                venue = paper.get('venue', 'N/A')
                abstract = paper.get('abstract', 'N/A')
                citations = paper.get('num_citations', 0)
                url = paper.get('pub_url', 'N/A')
                
                # Format author list if it's a list
                if isinstance(authors, list):
                    authors = ', '.join(authors)
                
                paper_info = {
                    'title': title,
                    'authors': authors,
                    'year': year,
                    'venue': venue,
                    'abstract': abstract[:300] + '...' if len(str(abstract)) > 300 else abstract,
                    'citations': citations,
                    'url': url
                }
                
                papers.append(paper_info)
                count += 1
                
            except Exception as e:
                logger.warning(f"Error processing paper: {e}")
                continue
            
            await _polite_delay()
        
        if not papers:
            return [types.TextContent(
                type="text",
                text=f"No papers found for query: '{query}'"
            )]
        
        # Format results
        result_text = f"Found {len(papers)} papers for query: '{query}'\n\n"
        
        for i, paper in enumerate(papers, 1):
            result_text += f"**{i}. {paper['title']}**\n"
            result_text += f"   Authors: {paper['authors']}\n"
            result_text += f"   Year: {paper['year']}\n"
            result_text += f"   Venue: {paper['venue']}\n"
            result_text += f"   Citations: {paper['citations']}\n"
            if paper['abstract'] != 'N/A':
                result_text += f"   Abstract: {paper['abstract']}\n"
            if paper['url'] != 'N/A':
                result_text += f"   URL: {paper['url']}\n"
            result_text += "\n"
        
        return [types.TextContent(type="text", text=result_text)]
        
    except Exception as e:
        logger.error(f"Error searching papers: {e}")
        return [types.TextContent(
            type="text",
            text=f"Error searching for papers: {str(e)}"
        )]

async def search_author(arguments: Dict[str, Any]) -> List[types.TextContent]:
    """Search for authors on Google Scholar."""
    author_name = arguments.get("author_name", "")
    max_results = min(arguments.get("max_results", 5), 10)
    
    if not author_name:
        return [types.TextContent(
            type="text",
            text="Error: Author name is required"
        )]
    
    try:
        search_query = sch_module.search_author(author_name)
        authors = []
        count = 0

        await _polite_delay()
        
        for author in search_query:
            if count >= max_results:
                break
                
            try:
                # Get author details
                author_info = {
                    'name': author.get('name', 'N/A'),
                    'affiliation': author.get('affiliation', 'N/A'),
                    'email': author.get('email', 'N/A'),
                    'interests': author.get('interests', []),
                    'citedby': author.get('citedby', 0),
                    'scholar_id': author.get('scholar_id', 'N/A'),
                    'url': f"https://scholar.google.com/citations?user={author.get('scholar_id', '')}" if author.get('scholar_id') else 'N/A'
                }
                
                authors.append(author_info)
                count += 1
                
            except Exception as e:
                logger.warning(f"Error processing author: {e}")
                continue
            
            await _polite_delay()
        
        if not authors:
            return [types.TextContent(
                type="text",
                text=f"No authors found for: '{author_name}'"
            )]
        
        # Format results
        result_text = f"Found {len(authors)} authors for: '{author_name}'\n\n"
        
        for i, author in enumerate(authors, 1):
            result_text += f"**{i}. {author['name']}**\n"
            result_text += f"   Affiliation: {author['affiliation']}\n"
            if author['email'] != 'N/A':
                result_text += f"   Email: {author['email']}\n"
            if author['interests']:
                result_text += f"   Research Interests: {', '.join(author['interests'])}\n"
            result_text += f"   Total Citations: {author['citedby']}\n"
            if author['url'] != 'N/A':
                result_text += f"   Scholar Profile: {author['url']}\n"
            result_text += "\n"
        
        return [types.TextContent(type="text", text=result_text)]
        
    except Exception as e:
        logger.error(f"Error searching authors: {e}")
        return [types.TextContent(
            type="text",
            text=f"Error searching for authors: {str(e)}"
        )]

async def get_paper_details(arguments: Dict[str, Any]) -> List[types.TextContent]:
    """Get detailed information about a specific paper."""
    title = arguments.get("title", "")
    author = arguments.get("author", "")
    
    if not title:
        return [types.TextContent(
            type="text",
            text="Error: Paper title is required"
        )]
    
    try:
        # Search for the specific paper
        search_query = f'"{title}"'
        if author:
            search_query += f' author:"{author}"'
        
        search_results = sch_module.search_pubs(search_query)

        await _polite_delay()
        
        for paper in search_results:
            try:
                # Check if this is likely the right paper
                paper_title = paper.get('title', '')
                if title.lower() in paper_title.lower() or paper_title.lower() in title.lower():
                    
                    # Get detailed information
                    details = {
                        'title': paper.get('title', 'N/A'),
                        'authors': paper.get('author', 'N/A'),
                        'year': paper.get('year', 'N/A'),
                        'venue': paper.get('venue', 'N/A'),
                        'abstract': paper.get('abstract', 'N/A'),
                        'citations': paper.get('num_citations', 0),
                        'url': paper.get('pub_url', 'N/A'),
                        'eprint_url': paper.get('eprint_url', 'N/A')
                    }
                    
                    # Format author list if it's a list
                    if isinstance(details['authors'], list):
                        details['authors'] = ', '.join(details['authors'])
                    
                    # Format results
                    result_text = f"**Paper Details**\n\n"
                    result_text += f"**Title:** {details['title']}\n\n"
                    result_text += f"**Authors:** {details['authors']}\n\n"
                    result_text += f"**Year:** {details['year']}\n\n"
                    result_text += f"**Venue:** {details['venue']}\n\n"
                    result_text += f"**Citations:** {details['citations']}\n\n"
                    
                    if details['abstract'] != 'N/A':
                        result_text += f"**Abstract:**\n{details['abstract']}\n\n"
                    
                    if details['url'] != 'N/A':
                        result_text += f"**URL:** {details['url']}\n\n"
                    
                    if details['eprint_url'] != 'N/A':
                        result_text += f"**PDF URL:** {details['eprint_url']}\n\n"
                    
                    return [types.TextContent(type="text", text=result_text)]
                    
            except Exception as e:
                logger.warning(f"Error processing paper details: {e}")
                continue
            
            await _polite_delay()
        
        return [types.TextContent(
            type="text",
            text=f"Paper not found: '{title}'"
        )]
        
    except Exception as e:
        logger.error(f"Error getting paper details: {e}")
        return [types.TextContent(
            type="text",
            text=f"Error getting paper details: {str(e)}"
        )]

async def get_citation_info(arguments: Dict[str, Any]) -> List[types.TextContent]:
    """Get citation information and metrics for a paper."""
    title = arguments.get("title", "")
    author = arguments.get("author", "")
    
    if not title:
        return [types.TextContent(
            type="text",
            text="Error: Paper title is required"
        )]
    
    try:
        # Search for the specific paper
        search_query = f'"{title}"'
        if author:
            search_query += f' author:"{author}"'
        
        search_results = sch_module.search_pubs(search_query)

        await _polite_delay()
        
        for paper in search_results:
            try:
                # Check if this is likely the right paper
                paper_title = paper.get('title', '')
                if title.lower() in paper_title.lower() or paper_title.lower() in title.lower():
                    
                    citations = paper.get('num_citations', 0)
                    year = paper.get('year', 'N/A')
                    
                    # Calculate some basic metrics
                    current_year = 2024
                    if year != 'N/A' and isinstance(year, int):
                        years_since_pub = current_year - year
                        citations_per_year = citations / max(years_since_pub, 1) if years_since_pub > 0 else citations
                    else:
                        citations_per_year = 0
                    
                    result_text = f"**Citation Information for:** {paper_title}\n\n"
                    result_text += f"**Total Citations:** {citations}\n"
                    result_text += f"**Publication Year:** {year}\n"
                    
                    if year != 'N/A':
                        result_text += f"**Citations per Year:** {citations_per_year:.1f}\n"
                    
                    # Citation impact assessment
                    if citations >= 1000:
                        impact = "Very High Impact"
                    elif citations >= 100:
                        impact = "High Impact"
                    elif citations >= 50:
                        impact = "Moderate Impact"
                    elif citations >= 10:
                        impact = "Some Impact"
                    else:
                        impact = "Limited Impact"
                    
                    result_text += f"**Impact Assessment:** {impact}\n\n"
                    
                    return [types.TextContent(type="text", text=result_text)]
                    
            except Exception as e:
                logger.warning(f"Error processing citation info: {e}")
                continue
            
            await _polite_delay()
        
        return [types.TextContent(
            type="text",
            text=f"Paper not found for citation analysis: '{title}'"
        )]
        
    except Exception as e:
        logger.error(f"Error getting citation info: {e}")
        return [types.TextContent(
            type="text",
            text=f"Error getting citation information: {str(e)}"
        )]

async def main():
    # Import here to avoid issues if mcp package is not available
    from mcp.server.stdio import stdio_server
    
    async with stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="google-scholar-mcp",
                server_version="0.1.0",
                capabilities=server.get_capabilities(
                    notification_options=NotificationOptions(),
                    experimental_capabilities={},
                ),
            ),
        )

if __name__ == "__main__":
    asyncio.run(main()) 