import requests
import os
import time
import logging
from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta
from pathlib import Path
import json

class FacebookAdLibraryClient:
    """
    Facebook Ad Library API Client

    Handles authentication, ad searching, and creative asset downloading
    from Facebook's Ad Library API.
    """

    def __init__(self, app_id: str = None, app_secret: str = None, access_token: str = None):
        print("🔗 Initializing Facebook Ad Library Client...")

        # API configuration
        self.base_url = "https://graph.facebook.com/v19.0"
        self.ad_library_url = f"{self.base_url}/ads_archive"

        # Authentication
        self.app_id = app_id or os.getenv('FACEBOOK_APP_ID')
        self.app_secret = app_secret or os.getenv('FACEBOOK_APP_SECRET')
        self.access_token = access_token or os.getenv('FACEBOOK_ACCESS_TOKEN')

        # Rate limiting
        self.requests_per_hour = 200  # Facebook's default rate limit
        self.request_count = 0
        self.rate_limit_reset = time.time() + 3600

        # Supported countries (Ad Library API limitation)
        self.supported_countries = {
            'US': 'United States',
            'GB': 'United Kingdom',
            'BR': 'Brazil',
            'EU': 'European Union',
            'ALL': 'Global (Political ads only)'
        }

        self._validate_credentials()
        print("   ✅ Facebook Ad Library Client ready")

    def _validate_credentials(self):
        """Validate API credentials"""
        missing = []
        if not self.app_id:
            missing.append('FACEBOOK_APP_ID')
        if not self.app_secret:
            missing.append('FACEBOOK_APP_SECRET')

        if missing:
            print(f"   ⚠️  Missing credentials: {', '.join(missing)}")
            print("   💡 Set environment variables or pass them to the constructor")
            return False

        # Generate access token if not provided
        if not self.access_token:
            print("   🔑 Generating app access token...")
            self.access_token = self._generate_app_access_token()

        return True

    def _generate_app_access_token(self) -> str:
        """Generate app access token for API requests"""
        try:
            url = f"{self.base_url}/oauth/access_token"
            params = {
                'grant_type': 'client_credentials',
                'client_id': self.app_id,
                'client_secret': self.app_secret
            }

            response = requests.get(url, params=params)
            response.raise_for_status()

            token_data = response.json()
            return token_data.get('access_token')

        except Exception as e:
            print(f"   ❌ Failed to generate access token: {e}")
            return None

    def _check_rate_limit(self):
        """Check and enforce API rate limiting"""
        current_time = time.time()

        # Reset counter if hour has passed
        if current_time > self.rate_limit_reset:
            self.request_count = 0
            self.rate_limit_reset = current_time + 3600

        # Check if we've hit the limit
        if self.request_count >= self.requests_per_hour:
            sleep_time = self.rate_limit_reset - current_time
            if sleep_time > 0:
                print(f"   ⏳ Rate limit reached, sleeping for {sleep_time:.0f} seconds...")
                time.sleep(sleep_time + 1)
                self.request_count = 0
                self.rate_limit_reset = time.time() + 3600

    def search_ads(self,
                   search_terms: str = None,
                   ad_reached_countries: str = 'US',
                   ad_type: str = 'ALL',
                   media_type: str = 'ALL',
                   start_date: str = None,
                   end_date: str = None,
                   limit: int = 100) -> Dict[str, Any]:
        """
        Search for ads in the Facebook Ad Library

        Args:
            search_terms: Keywords to search for
            ad_reached_countries: Country codes (US, GB, BR, EU, ALL)
            ad_type: ALL, POLITICAL_AND_ISSUE_ADS, or REGULAR
            media_type: ALL, VIDEO, IMAGE
            start_date: YYYY-MM-DD format
            end_date: YYYY-MM-DD format
            limit: Number of results to return (max 5000)

        Returns:
            Dict containing ad search results
        """
        print(f"🔍 Searching Facebook ads...")
        print(f"   Terms: {search_terms or 'Any'}")
        print(f"   Country: {ad_reached_countries}")
        print(f"   Type: {ad_type}")

        if not self.access_token:
            return {"error": "No access token available"}

        self._check_rate_limit()

        # Build query parameters
        params = {
            'access_token': self.access_token,
            'ad_reached_countries': ad_reached_countries,
            'ad_type': ad_type,
            'limit': min(limit, 5000),  # API maximum
            'fields': 'id,ad_creation_time,ad_creative_bodies,ad_creative_link_captions,ad_creative_link_descriptions,ad_creative_link_titles,ad_delivery_start_time,ad_delivery_stop_time,ad_snapshot_url,currency,demographic_distribution,funding_entity,impressions,page_id,page_name,publisher_platforms,spend'
        }

        # Add optional parameters
        if search_terms:
            params['search_terms'] = search_terms
        if media_type and media_type != 'ALL':
            # Facebook API expects specific values for media_type
            media_mapping = {
                'VIDEO': 'VIDEO',
                'IMAGE': 'IMAGE'
            }
            if media_type in media_mapping:
                params['media_type'] = media_mapping[media_type]
        if start_date:
            params['ad_delivery_date_min'] = start_date
        if end_date:
            params['ad_delivery_date_max'] = end_date

        try:
            response = requests.get(self.ad_library_url, params=params)
            self.request_count += 1

            response.raise_for_status()
            data = response.json()

            ads_found = len(data.get('data', []))
            print(f"   ✅ Found {ads_found} ads")

            return data

        except requests.exceptions.HTTPError as e:
            error_data = {}
            try:
                error_data = response.json()
            except:
                pass

            print(f"   ❌ API Error: {e}")
            if error_data.get('error'):
                error_msg = error_data['error'].get('message', 'Unknown error')
                error_type = error_data['error'].get('type', 'Unknown')
                error_code = error_data['error'].get('code', 'Unknown')
                print(f"   Error details: {error_msg} (Type: {error_type}, Code: {error_code})")
                print(f"   Full error response: {error_data}")

                # Provide helpful troubleshooting suggestions
                if error_type == 'OAuthException':
                    print("   💡 This is an authentication/permission error:")
                    print("      - Verify your App ID and App Secret are correct")
                    print("      - Check if your Facebook app is approved for Ad Library API access")
                    print("      - Ensure you have completed identity verification")
                    print("      - Try accessing Facebook's Ad Library directly at facebook.com/ads/library")

            return {"error": f"API request failed: {e}", "details": error_data}

        except Exception as e:
            print(f"   ❌ Request failed: {e}")
            return {"error": f"Request failed: {e}"}

    def download_ad_creative(self, ad_snapshot_url: str, output_dir: str, ad_id: str) -> Dict[str, Any]:
        """
        Download creative assets from an ad snapshot URL

        Args:
            ad_snapshot_url: URL to the ad snapshot
            output_dir: Directory to save downloaded assets
            ad_id: Unique identifier for the ad

        Returns:
            Dict with download results and file paths
        """
        print(f"📥 Downloading creative for ad {ad_id}...")

        try:
            # Create output directory
            ad_dir = Path(output_dir) / f"ad_{ad_id}"
            ad_dir.mkdir(parents=True, exist_ok=True)

            # For now, save the snapshot URL and metadata
            # Note: Facebook's Ad Library API doesn't directly provide creative assets
            # The snapshot URL leads to a webpage, not direct media files

            metadata = {
                "ad_id": ad_id,
                "snapshot_url": ad_snapshot_url,
                "download_time": datetime.now().isoformat(),
                "status": "url_saved",
                "note": "Direct creative download not available via API - snapshot URL saved"
            }

            # Save metadata
            metadata_file = ad_dir / "metadata.json"
            with open(metadata_file, 'w') as f:
                json.dump(metadata, f, indent=2)

            print(f"   ✅ Metadata saved to {metadata_file}")

            return {
                "success": True,
                "ad_id": ad_id,
                "metadata_file": str(metadata_file),
                "snapshot_url": ad_snapshot_url,
                "note": "API limitation: Creative assets require web scraping for direct download"
            }

        except Exception as e:
            print(f"   ❌ Download failed: {e}")
            return {
                "success": False,
                "ad_id": ad_id,
                "error": str(e)
            }

    def get_ad_insights(self, ad_id: str) -> Dict[str, Any]:
        """
        Get detailed insights for a specific ad (if available)

        Args:
            ad_id: Facebook ad ID

        Returns:
            Dict containing ad insights
        """
        print(f"📊 Getting insights for ad {ad_id}...")

        if not self.access_token:
            return {"error": "No access token available"}

        self._check_rate_limit()

        try:
            url = f"{self.base_url}/{ad_id}"
            params = {
                'access_token': self.access_token,
                'fields': 'id,name,status,created_time,updated_time'
            }

            response = requests.get(url, params=params)
            self.request_count += 1

            response.raise_for_status()
            return response.json()

        except Exception as e:
            print(f"   ❌ Insights request failed: {e}")
            return {"error": f"Failed to get insights: {e}"}

    def test_connection(self) -> Dict[str, Any]:
        """
        Test API connection and permissions

        Returns:
            Dict with connection test results
        """
        print("🧪 Testing Facebook Ad Library API connection...")

        if not self.access_token:
            return {"success": False, "error": "No access token available"}

        try:
            # Simple test query - search for political ads in the US (broader access)
            result = self.search_ads(
                ad_reached_countries='US',
                ad_type='POLITICAL_AND_ISSUE_ADS',
                limit=1
            )

            if "error" in result:
                return {"success": False, "error": result["error"]}

            ads_count = len(result.get('data', []))
            return {
                "success": True,
                "message": f"Connection successful! Found {ads_count} ads in test query",
                "rate_limit_remaining": self.requests_per_hour - self.request_count,
                "supported_countries": list(self.supported_countries.keys())
            }

        except Exception as e:
            return {"success": False, "error": f"Connection test failed: {e}"}

def create_facebook_client(**kwargs) -> FacebookAdLibraryClient:
    """
    Factory function to create a Facebook Ad Library client

    Args:
        **kwargs: Arguments to pass to FacebookAdLibraryClient constructor

    Returns:
        Configured FacebookAdLibraryClient instance
    """
    return FacebookAdLibraryClient(**kwargs)