import requests
import random
import time
import json
import pandas as pd
from typing import List, Dict, Optional
from pytrends.request import TrendReq
from datetime import datetime
from requests.exceptions import RequestException
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

class AITrendAnalyzer:
    """
    A class for analyzing AI-related trending topics using Google Trends.
    Includes proper data parsing and error handling.
    """
    
    def __init__(self, 
                 debug: bool = True,
                 rate_limit_delay: int = 3):
        """
        Initialize the AITrendAnalyzer.
        
        Args:
            debug: Enable debug logging
            rate_limit_delay: Delay between API requests in seconds
        """
        self.debug = debug
        self.rate_limit_delay = rate_limit_delay
        self.initialize_pytrends()
        
        # AI-related seed keywords (reduced batch size for testing)
        self.seed_keywords = [
            "Artificial Intelligence",
            "ChatGPT",
            "Machine Learning"
        ]

    def debug_print(self, message: str) -> None:
        """Print debug messages if debug mode is enabled."""
        if self.debug:
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            print(f"[DEBUG {timestamp}] {message}")

    def initialize_pytrends(self) -> None:
        """Initialize or reinitialize the pytrends client."""
        try:
            # Create a session with custom retry strategy
            session = requests.Session()
            
            # Configure retry strategy
            retry_strategy = Retry(
                total=3,
                backoff_factor=0.5,
                allowed_methods=["GET", "POST"],
                status_forcelist=[429, 500, 502, 503, 504]
            )
            
            adapter = HTTPAdapter(max_retries=retry_strategy)
            session.mount("https://", adapter)
            session.mount("http://", adapter)
            
            self.pytrends = TrendReq(
                hl='en-US',
                tz=360,
                timeout=(10, 25),
                requests_args={'verify': True}
            )
            self.pytrends.requests = session
            
            self.debug_print("Initialized pytrends client")
            
        except Exception as e:
            self.debug_print(f"Error initializing pytrends: {str(e)}")
            raise

    def safe_get_dataframe_values(self, df: pd.DataFrame, column_name: str) -> List[str]:
        """Safely extract values from a dataframe column."""
        if df is None or df.empty:
            return []
        
        try:
            if column_name in df.columns:
                return df[column_name].astype(str).tolist()
            return []
        except Exception as e:
            self.debug_print(f"Error extracting values from dataframe: {str(e)}")
            return []

    def get_ai_trending_topics(self) -> List[str]:
        """
        Get trending AI-related topics using multiple methods.
        
        Returns:
            List of trending topics
        """
        trending_topics = set()
        
        for keyword in self.seed_keywords:
            self.debug_print(f"Processing keyword: {keyword}")
            
            try:
                # Build payload with single keyword
                self.pytrends.build_payload(
                    kw_list=[keyword],
                    timeframe='today 3-m'
                )
                
                # Get interest over time first to validate the request
                interest_over_time = self.pytrends.interest_over_time()
                if interest_over_time is None or interest_over_time.empty:
                    self.debug_print(f"No interest data found for {keyword}")
                    continue
                
                self.debug_print(f"Successfully fetched interest data for {keyword}")
                
                # Get related topics
                related_topics = self.pytrends.related_topics()
                if keyword in related_topics:
                    topic_data = related_topics[keyword]
                    
                    # Process rising topics
                    if 'rising' in topic_data:
                        rising_df = topic_data['rising']
                        topics = self.safe_get_dataframe_values(rising_df, 'topic_title')
                        if topics:
                            trending_topics.update(topics[:5])
                            self.debug_print(f"Found {len(topics[:5])} rising topics for {keyword}")
                    
                    # Process top topics
                    if 'top' in topic_data:
                        top_df = topic_data['top']
                        topics = self.safe_get_dataframe_values(top_df, 'topic_title')
                        if topics:
                            trending_topics.update(topics[:5])
                            self.debug_print(f"Found {len(topics[:5])} top topics for {keyword}")
                
                # Get related queries
                related_queries = self.pytrends.related_queries()
                if keyword in related_queries:
                    query_data = related_queries[keyword]
                    
                    # Process rising queries
                    if 'rising' in query_data and query_data['rising'] is not None:
                        rising_queries = self.safe_get_dataframe_values(query_data['rising'], 'query')
                        if rising_queries:
                            trending_topics.update(rising_queries[:3])
                            self.debug_print(f"Found {len(rising_queries[:3])} rising queries for {keyword}")
                    
                    # Process top queries
                    if 'top' in query_data and query_data['top'] is not None:
                        top_queries = self.safe_get_dataframe_values(query_data['top'], 'query')
                        if top_queries:
                            trending_topics.update(top_queries[:3])
                            self.debug_print(f"Found {len(top_queries[:3])} top queries for {keyword}")
                
                time.sleep(self.rate_limit_delay)
                
            except Exception as e:
                self.debug_print(f"Error processing keyword {keyword}: {str(e)}")
                continue
        
        return list(trending_topics)

    def analyze_trends(self, output_file: Optional[str] = None) -> Dict:
        """
        Analyze AI trends and store results.
        
        Args:
            output_file: Optional file path to save results
            
        Returns:
            Dictionary containing analysis results
        """
        self.debug_print("Starting trend analysis...")
        
        topics = self.get_ai_trending_topics()
        if not topics:
            self.debug_print("No trending topics found.")
            return {"error": "No trending topics found"}
        
        results = {
            "timestamp": datetime.now().isoformat(),
            "top_topics": topics,
            "total_topics": len(topics)
        }
        
        # Save results if output file specified
        if output_file:
            try:
                with open(output_file, 'w') as f:
                    json.dump(results, f, indent=4)
                self.debug_print(f"Results saved to {output_file}")
            except IOError as e:
                self.debug_print(f"Error saving results: {str(e)}")
        
        return results

def main():
    """Example usage of the AITrendAnalyzer."""
    analyzer = AITrendAnalyzer(
        debug=True,
        rate_limit_delay=3
    )
    
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    results = analyzer.analyze_trends(f'ai_trends_{timestamp}.json')
    
    if "error" not in results:
        print("\nTop trending AI topics:")
        for i, topic in enumerate(results["top_topics"], 1):
            print(f"{i}. {topic}")
    else:
        print("Analysis failed:", results["error"])

if __name__ == "__main__":
    main() (venv) ➜ scripts python3 gtrends.py [DEBUG 2024-11-18 21:03:22] Initialized pytrends client [DEBUG 2024-11-18 21:03:22] Starting trend analysis... [DEBUG 2024-11-18 21:03:22] Processing keyword: Artificial Intelligence [DEBUG 2024-11-18 21:03:22] Error processing keyword Artificial Intelligence: The request failed: Google returned a response with code 429 [DEBUG 2024-11-18 21:03:22] Processing keyword: ChatGPT [DEBUG 2024-11-18 21:03:23] Error processing keyword ChatGPT: The request failed: Google returned a response with code 429 [DEBUG 2024-11-18 21:03:23] Processing keyword: Machine Learning [DEBUG 2024-11-18 21:03:23] Error processing keyword Machine Learning: The request failed: Google returned a response with code 429 [DEBUG 2024-11-18 21:03:23] No trending topics found. Analysis failed: No trending topics found (venv) ➜ scripts