#!/usr/bin/env python3
"""
Google Search Scraper PRO
Suporta múltiplas APIs profissionais para resultados confiáveis e em escala
"""

import requests
from bs4 import BeautifulSoup
import sys
import json
import os
from urllib.parse import quote_plus
from datetime import datetime
from typing import List, Dict, Optional

class GoogleScraperPro:
    """Scraper profissional com suporte a múltiplas APIs"""

    def __init__(self, api_provider='native', api_key=None):
        """
        Args:
            api_provider: 'native', 'dataforseo', 'serpapi', 'scaleserp', 'brightdata'
            api_key: API key para o provedor escolhido
        """
        self.api_provider = api_provider
        self.api_key = api_key or os.getenv(f'{api_provider.upper()}_API_KEY')
        self.results = []

    # ========== NATIVE SCRAPING (sem API) ==========
    def scrape_native(self, query: str, num_results: int = 10) -> List[Dict]:
        """Scraping direto do Google (método original)"""

        headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language': 'pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7',
            'Accept-Encoding': 'gzip, deflate, br',
            'Connection': 'keep-alive',
        }

        url = f'https://www.google.com/search?q={quote_plus(query)}&num={num_results}'

        try:
            response = requests.get(url, headers=headers, timeout=10)
            response.raise_for_status()
            soup = BeautifulSoup(response.text, 'html.parser')

            results = []
            search_results = soup.find_all('div', class_='g')

            for idx, result in enumerate(search_results[:num_results], 1):
                try:
                    title_elem = result.find('h3')
                    title = title_elem.get_text() if title_elem else 'N/A'

                    link_elem = result.find('a')
                    link = link_elem.get('href') if link_elem else 'N/A'

                    desc_elem = result.find('div', class_=['VwiC3b', 'yXK7lf'])
                    description = desc_elem.get_text() if desc_elem else 'N/A'

                    results.append({
                        'position': idx,
                        'title': title,
                        'link': link,
                        'description': description
                    })
                except:
                    continue

            return results

        except Exception as e:
            print(f"❌ Erro no scraping nativo: {e}")
            return []

    # ========== DATAFORSEO API ==========
    def scrape_dataforseo(self, query: str, num_results: int = 10) -> List[Dict]:
        """
        DataForSEO - API profissional para SEO/SERP
        https://dataforseo.com/
        Preço: ~$0.003 por consulta
        """

        if not self.api_key:
            print("❌ DataForSEO API Key não encontrada")
            print("   Configure: export DATAFORSEO_API_KEY='seu_login:sua_senha'")
            return []

        url = "https://api.dataforseo.com/v3/serp/google/organic/live/advanced"

        # Login:senha em base64
        login, password = self.api_key.split(':')

        payload = [{
            "keyword": query,
            "location_code": 2076,  # Brasil
            "language_code": "pt",
            "device": "desktop",
            "os": "macos",
            "depth": num_results
        }]

        try:
            response = requests.post(
                url,
                json=payload,
                auth=(login, password),
                timeout=30
            )
            response.raise_for_status()

            data = response.json()

            if data['status_code'] != 20000:
                print(f"❌ Erro DataForSEO: {data.get('status_message')}")
                return []

            results = []
            items = data['tasks'][0]['result'][0].get('items', [])

            for idx, item in enumerate(items[:num_results], 1):
                if item['type'] == 'organic':
                    results.append({
                        'position': idx,
                        'title': item.get('title', 'N/A'),
                        'link': item.get('url', 'N/A'),
                        'description': item.get('description', 'N/A'),
                        'domain': item.get('domain', 'N/A'),
                        'breadcrumb': item.get('breadcrumb', 'N/A')
                    })

            return results

        except Exception as e:
            print(f"❌ Erro DataForSEO: {e}")
            return []

    # ========== SERPAPI ==========
    def scrape_serpapi(self, query: str, num_results: int = 10) -> List[Dict]:
        """
        SerpAPI - API popular e fácil de usar
        https://serpapi.com/
        Preço: 100 consultas grátis/mês, depois ~$50/mês
        """

        if not self.api_key:
            print("❌ SerpAPI Key não encontrada")
            print("   Configure: export SERPAPI_API_KEY='sua_chave'")
            return []

        url = "https://serpapi.com/search"

        params = {
            'q': query,
            'api_key': self.api_key,
            'num': num_results,
            'gl': 'br',  # Brasil
            'hl': 'pt',  # Português
            'engine': 'google'
        }

        try:
            response = requests.get(url, params=params, timeout=30)
            response.raise_for_status()

            data = response.json()

            results = []
            organic_results = data.get('organic_results', [])

            for idx, item in enumerate(organic_results[:num_results], 1):
                results.append({
                    'position': idx,
                    'title': item.get('title', 'N/A'),
                    'link': item.get('link', 'N/A'),
                    'description': item.get('snippet', 'N/A'),
                    'displayed_link': item.get('displayed_link', 'N/A')
                })

            return results

        except Exception as e:
            print(f"❌ Erro SerpAPI: {e}")
            return []

    # ========== SCALESERP ==========
    def scrape_scaleserp(self, query: str, num_results: int = 10) -> List[Dict]:
        """
        ScaleSERP - API rápida e escalável
        https://scaleserp.com/
        Preço: ~$0.002 por consulta
        """

        if not self.api_key:
            print("❌ ScaleSERP API Key não encontrada")
            print("   Configure: export SCALESERP_API_KEY='sua_chave'")
            return []

        url = "https://api.scaleserp.com/search"

        params = {
            'api_key': self.api_key,
            'q': query,
            'num': num_results,
            'gl': 'br',
            'hl': 'pt'
        }

        try:
            response = requests.get(url, params=params, timeout=30)
            response.raise_for_status()

            data = response.json()

            results = []
            organic_results = data.get('organic_results', [])

            for idx, item in enumerate(organic_results[:num_results], 1):
                results.append({
                    'position': idx,
                    'title': item.get('title', 'N/A'),
                    'link': item.get('link', 'N/A'),
                    'description': item.get('snippet', 'N/A'),
                    'domain': item.get('domain', 'N/A')
                })

            return results

        except Exception as e:
            print(f"❌ Erro ScaleSERP: {e}")
            return []

    # ========== BRIGHT DATA (ex-Luminati) ==========
    def scrape_brightdata(self, query: str, num_results: int = 10) -> List[Dict]:
        """
        Bright Data - Líder em web scraping profissional
        https://brightdata.com/
        Preço: Planos customizados
        """

        if not self.api_key:
            print("❌ Bright Data API Key não encontrada")
            print("   Configure: export BRIGHTDATA_API_KEY='sua_chave'")
            return []

        # Bright Data usa proxy ou API direta
        # Exemplo simplificado usando SERP API deles
        url = "https://api.brightdata.com/serp/google"

        headers = {
            'Authorization': f'Bearer {self.api_key}',
            'Content-Type': 'application/json'
        }

        payload = {
            'query': query,
            'country': 'br',
            'language': 'pt',
            'num_results': num_results
        }

        try:
            response = requests.post(url, headers=headers, json=payload, timeout=30)
            response.raise_for_status()

            data = response.json()

            results = []
            for idx, item in enumerate(data.get('organic_results', [])[:num_results], 1):
                results.append({
                    'position': idx,
                    'title': item.get('title', 'N/A'),
                    'link': item.get('url', 'N/A'),
                    'description': item.get('description', 'N/A')
                })

            return results

        except Exception as e:
            print(f"❌ Erro Bright Data: {e}")
            return []

    # ========== MÉTODO PRINCIPAL ==========
    def search(self, query: str, num_results: int = 10, auto_save: bool = True) -> List[Dict]:
        """
        Busca usando o provedor configurado

        Args:
            query: Palavra-chave
            num_results: Número de resultados
            auto_save: Salvar automaticamente em JSON

        Returns:
            Lista de resultados
        """

        print(f"🔍 Buscando: '{query}' com {self.api_provider.upper()}")
        print(f"📊 Resultados solicitados: {num_results}\n")

        # Selecionar método baseado no provedor
        if self.api_provider == 'native':
            self.results = self.scrape_native(query, num_results)
        elif self.api_provider == 'dataforseo':
            self.results = self.scrape_dataforseo(query, num_results)
        elif self.api_provider == 'serpapi':
            self.results = self.scrape_serpapi(query, num_results)
        elif self.api_provider == 'scaleserp':
            self.results = self.scrape_scaleserp(query, num_results)
        elif self.api_provider == 'brightdata':
            self.results = self.scrape_brightdata(query, num_results)
        else:
            print(f"❌ Provedor desconhecido: {self.api_provider}")
            return []

        # Salvar automaticamente
        if auto_save and self.results:
            filename = f"google_results_{query.replace(' ', '_')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
            self.save_to_json(filename)

        return self.results

    def print_results(self):
        """Imprime resultados formatados"""

        if not self.results:
            print("❌ Nenhum resultado encontrado")
            return

        print(f"✅ Encontrados {len(self.results)} resultados:\n")
        print("=" * 100)

        for r in self.results:
            print(f"\n#{r['position']} - {r['title']}")
            print(f"🔗 {r['link']}")
            desc = r['description'][:200] + "..." if len(r['description']) > 200 else r['description']
            print(f"📝 {desc}")
            print("-" * 100)

    def save_to_json(self, filename: str):
        """Salva resultados em JSON"""
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump({
                    'query': getattr(self, 'last_query', ''),
                    'provider': self.api_provider,
                    'timestamp': datetime.now().isoformat(),
                    'total_results': len(self.results),
                    'results': self.results
                }, f, ensure_ascii=False, indent=2)
            print(f"\n💾 Resultados salvos em: {filename}")
        except Exception as e:
            print(f"❌ Erro ao salvar: {e}")

    def get_all_links(self) -> List[str]:
        """Retorna apenas os links encontrados"""
        return [r['link'] for r in self.results if r['link'] != 'N/A']


def main():
    """Interface CLI"""

    print("=" * 100)
    print("🚀 GOOGLE SEARCH SCRAPER PRO")
    print("=" * 100 + "\n")

    # Selecionar provedor
    print("📡 Provedores disponíveis:")
    print("  1. Native (scraping direto - grátis, pode ter limitações)")
    print("  2. DataForSEO (profissional - $0.003/consulta)")
    print("  3. SerpAPI (popular - 100 grátis/mês)")
    print("  4. ScaleSERP (escalável - $0.002/consulta)")
    print("  5. Bright Data (premium - planos customizados)\n")

    provider_map = {
        '1': 'native',
        '2': 'dataforseo',
        '3': 'serpapi',
        '4': 'scaleserp',
        '5': 'brightdata'
    }

    choice = input("Escolha o provedor (1-5, padrão 1): ").strip() or '1'
    provider = provider_map.get(choice, 'native')

    # Palavra-chave
    if len(sys.argv) > 1:
        query = ' '.join(sys.argv[1:])
    else:
        query = input("\n🔍 Digite a palavra-chave: ").strip()

    if not query:
        print("❌ Palavra-chave não pode estar vazia")
        sys.exit(1)

    # Número de resultados
    try:
        num = input("📊 Quantos resultados? (padrão 10): ").strip()
        num_results = int(num) if num else 10
    except ValueError:
        num_results = 10

    # Criar scraper
    scraper = GoogleScraperPro(api_provider=provider)
    scraper.last_query = query

    # Buscar
    results = scraper.search(query, num_results, auto_save=True)

    # Exibir
    scraper.print_results()

    # Mostrar links
    links = scraper.get_all_links()
    print(f"\n🔗 {len(links)} links salvos automaticamente no JSON")

    print("\n✅ Concluído!")


if __name__ == '__main__':
    main()
