from fastmcp import FastMCP
from googleapiclient.discovery import build
from google.oauth2.service_account import Credentials
import os
import sys
import json
from pathlib import Path
from datetime import datetime, timedelta

# Configuration from environment variables
CREDENTIALS_PATH = os.getenv("GOOGLE_APPLICATION_CREDENTIALS")
GSC_SITE_URL = os.getenv("GSC_SITE_URL")  # e.g., "https://example.com/"

# Validate required environment variables
if not CREDENTIALS_PATH:
    print("ERROR: GOOGLE_APPLICATION_CREDENTIALS environment variable not set", file=sys.stderr)
    print("Please set it to the path of your service account JSON file", file=sys.stderr)
    sys.exit(1)

if not GSC_SITE_URL:
    print("ERROR: GSC_SITE_URL environment variable not set", file=sys.stderr)
    print("Please set it to your verified site URL (e.g., https://example.com/)", file=sys.stderr)
    sys.exit(1)

# Validate credentials file exists
if not os.path.exists(CREDENTIALS_PATH):
    print(f"ERROR: Credentials file not found: {CREDENTIALS_PATH}", file=sys.stderr)
    print("Please check the GOOGLE_APPLICATION_CREDENTIALS path", file=sys.stderr)
    sys.exit(1)

# Initialize FastMCP
mcp = FastMCP("Google Search Console")

# Initialize Google Search Console API client
def get_gsc_service():
    """Initialize and return Google Search Console API service"""
    try:
        credentials = Credentials.from_service_account_file(CREDENTIALS_PATH)
        service = build('searchconsole', 'v1', credentials=credentials)
        return service
    except Exception as e:
        print(f"Error initializing GSC service: {str(e)}", file=sys.stderr)
        raise

# Load dimensions and metrics from JSON files
def load_gsc_dimensions():
    """Load available GSC dimensions from JSON file"""
    try:
        script_dir = Path(__file__).parent
        with open(script_dir / "gsc_dimensions.json", "r") as f:
            return json.load(f)
    except FileNotFoundError:
        print("Warning: gsc_dimensions.json not found", file=sys.stderr)
        return {}

def load_gsc_metrics():
    """Load available GSC metrics from JSON file"""
    try:
        script_dir = Path(__file__).parent
        with open(script_dir / "gsc_metrics.json", "r") as f:
            return json.load(f)
    except FileNotFoundError:
        print("Warning: gsc_metrics.json not found", file=sys.stderr)
        return {}

@mcp.tool()
def list_gsc_sites():
    """
    List all sites verified in Google Search Console.
    
    Returns:
        List of verified sites with their permission levels.
    """
    try:
        service = get_gsc_service()
        sites = service.sites().list().execute()
        
        result = []
        for site in sites.get('siteEntry', []):
            result.append({
                'siteUrl': site['siteUrl'],
                'permissionLevel': site['permissionLevel']
            })
        
        return result
    except Exception as e:
        return {"error": f"Error fetching sites: {str(e)}"}

@mcp.tool()
def list_available_dimensions():
    """
    List all available GSC dimensions with their descriptions.
    
    Returns:
        List of dimension objects with api_name and description.
    """
    dimensions = load_gsc_dimensions()
    return dimensions.get('dimensions', [])

@mcp.tool()
def list_available_metrics():
    """
    List all available GSC metrics with their descriptions.
    
    Returns:
        List of metric objects with api_name and description.
    """
    metrics = load_gsc_metrics()
    return metrics.get('metrics', [])

@mcp.tool()
def get_search_analytics(
    dimensions=["query"],
    start_date=None,
    end_date=None,
    filters=None,
    search_type="web",
    row_limit=1000,
    start_row=0
):
    """
    Retrieve Google Search Console search analytics data.
    
    Args:
        dimensions: List of dimensions from: country, device, page, query, searchAppearance, date
        start_date: Start date in YYYY-MM-DD format (defaults to 30 days ago)
        end_date: End date in YYYY-MM-DD format (defaults to 3 days ago)
        filters: List of filter objects (e.g., [{"dimension": "country", "operator": "equals", "expression": "usa"}])
        search_type: Type of search ('web', 'image', 'video', 'news', 'discover', 'googleNews')
        row_limit: Maximum number of rows to return (max 25000)
        start_row: Starting row for pagination (0-based)
        
    Returns:
        Dictionary containing search analytics data with clicks, impressions, ctr, and position metrics.
    """
    try:
        # Handle string input for dimensions
        if isinstance(dimensions, str):
            try:
                dimensions = json.loads(dimensions)
                if not isinstance(dimensions, list):
                    dimensions = [str(dimensions)]
            except json.JSONDecodeError:
                dimensions = [d.strip() for d in dimensions.split(',')]
        
        # Validate dimensions
        valid_dimensions = ["country", "device", "page", "query", "searchAppearance", "date"]
        for dim in dimensions:
            if dim not in valid_dimensions:
                return {"error": f"Invalid dimension '{dim}'. Valid dimensions: {valid_dimensions}"}
        
        # Set default dates if not provided
        if not start_date:
            start_date = (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d')
        if not end_date:
            end_date = (datetime.now() - timedelta(days=3)).strftime('%Y-%m-%d')
        
        # Handle filters
        request_filters = []
        if filters:
            if isinstance(filters, str):
                try:
                    filters = json.loads(filters)
                except json.JSONDecodeError:
                    return {"error": "Invalid filters format. Expected JSON array."}
            
            for filter_item in filters:
                # Validate filter dimension
                filter_dim = filter_item.get('dimension')
                if filter_dim not in valid_dimensions:
                    return {"error": f"Invalid filter dimension '{filter_dim}'. Valid dimensions: {valid_dimensions}"}
                
                request_filters.append({
                    'dimension': filter_dim,
                    'operator': filter_item.get('operator', 'equals'),
                    'expression': filter_item.get('expression')
                })
        
        # Validate search type
        valid_search_types = ["web", "image", "video", "news", "discover", "googleNews"]
        if search_type not in valid_search_types:
            return {"error": f"Invalid search_type '{search_type}'. Valid types: {valid_search_types}"}
        
        # Build the request
        request = {
            'startDate': start_date,
            'endDate': end_date,
            'dimensions': dimensions,
            'searchType': search_type,
            'rowLimit': min(row_limit, 25000),  # GSC API limit
            'startRow': start_row
        }
        
        if request_filters:
            request['dimensionFilterGroups'] = [{
                'filters': request_filters
            }]
        
        # Execute the request
        service = get_gsc_service()
        response = service.searchanalytics().query(
            siteUrl=GSC_SITE_URL,
            body=request
        ).execute()
        
        # Format the response
        result = {
            'metadata': {
                'site_url': GSC_SITE_URL,
                'start_date': start_date,
                'end_date': end_date,
                'dimensions': dimensions,
                'search_type': search_type,
                'total_rows': len(response.get('rows', [])),
                'row_limit': row_limit,
                'start_row': start_row
            },
            'data': []
        }
        
        for row in response.get('rows', []):
            data_row = {}
            
            # Add dimension values
            if 'keys' in row:
                for i, dimension in enumerate(dimensions):
                    if i < len(row['keys']):
                        data_row[dimension] = row['keys'][i]
            
            # Add metric values (all GSC metrics are always returned)
            data_row['clicks'] = row.get('clicks', 0)
            data_row['impressions'] = row.get('impressions', 0)
            data_row['ctr'] = round(row.get('ctr', 0.0) * 100, 2)  # Convert to percentage
            data_row['position'] = round(row.get('position', 0.0), 1)
            
            result['data'].append(data_row)
        
        return result
        
    except Exception as e:
        error_message = f"Error fetching GSC data: {str(e)}"
        print(error_message, file=sys.stderr)
        return {"error": error_message}

@mcp.tool()
def get_sitemaps():
    """
    Get all sitemaps for the configured site.
    
    Returns:
        List of sitemaps with their status and details.
    """
    try:
        service = get_gsc_service()
        sitemaps = service.sitemaps().list(siteUrl=GSC_SITE_URL).execute()
        
        result = []
        for sitemap in sitemaps.get('sitemap', []):
            result.append({
                'path': sitemap.get('path'),
                'lastSubmitted': sitemap.get('lastSubmitted'),
                'isPending': sitemap.get('isPending', False),
                'isSitemapsIndex': sitemap.get('isSitemapsIndex', False),
                'type': sitemap.get('type'),
                'lastDownloaded': sitemap.get('lastDownloaded'),
                'warnings': sitemap.get('warnings', 0),
                'errors': sitemap.get('errors', 0)
            })
        
        return result
        
    except Exception as e:
        return {"error": f"Error fetching sitemaps: {str(e)}"}

@mcp.tool()
def submit_sitemap(sitemap_url):
    """
    Submit a sitemap to Google Search Console.
    
    Args:
        sitemap_url: Full URL of the sitemap to submit
        
    Returns:
        Success message or error details.
    """
    try:
        service = get_gsc_service()
        service.sitemaps().submit(
            siteUrl=GSC_SITE_URL,
            feedpath=sitemap_url
        ).execute()
        
        return {"success": f"Sitemap submitted successfully: {sitemap_url}"}
        
    except Exception as e:
        return {"error": f"Error submitting sitemap: {str(e)}"}

@mcp.tool()
def delete_sitemap(sitemap_url):
    """
    Delete a sitemap from Google Search Console.
    
    Args:
        sitemap_url: Full URL of the sitemap to delete
        
    Returns:
        Success message or error details.
    """
    try:
        service = get_gsc_service()
        service.sitemaps().delete(
            siteUrl=GSC_SITE_URL,
            feedpath=sitemap_url
        ).execute()
        
        return {"success": f"Sitemap deleted successfully: {sitemap_url}"}
        
    except Exception as e:
        return {"error": f"Error deleting sitemap: {str(e)}"}

# Start the server when run directly
if __name__ == "__main__":
    # Use stdio transport ONLY - this is critical for MCP with Claude
    print("Starting GSC MCP server...", file=sys.stderr)
    mcp.run(transport="stdio")