#!/usr/bin/env python3
"""
Facebook Ads CSV Bulk Upload Generator
Complete field mapping with validation for all campaign types
Author: Buba
Date: 2026-02-11
"""

import csv
import datetime
from typing import List, Dict, Optional
from enum import Enum


class CampaignObjective(Enum):
    """All supported Facebook campaign objectives"""
    OUTCOME_TRAFFIC = "OUTCOME_TRAFFIC"
    OUTCOME_SALES = "OUTCOME_SALES"
    OUTCOME_LEADS = "OUTCOME_LEADS"
    OUTCOME_ENGAGEMENT = "OUTCOME_ENGAGEMENT"
    OUTCOME_APP_PROMOTION = "OUTCOME_APP_PROMOTION"
    OUTCOME_AWARENESS = "OUTCOME_AWARENESS"


class OptimizationGoal(Enum):
    """Ad set optimization goals"""
    LINK_CLICKS = "LINK_CLICKS"
    LANDING_PAGE_VIEWS = "LANDING_PAGE_VIEWS"
    IMPRESSIONS = "IMPRESSIONS"
    REACH = "REACH"
    OFFSITE_CONVERSIONS = "OFFSITE_CONVERSIONS"
    THRUPLAY = "THRUPLAY"
    POST_ENGAGEMENT = "POST_ENGAGEMENT"


class BillingEvent(Enum):
    """Billing event types"""
    IMPRESSIONS = "IMPRESSIONS"
    LINK_CLICKS = "LINK_CLICKS"
    THRUPLAY = "THRUPLAY"


class CallToAction(Enum):
    """Call to action button types"""
    LEARN_MORE = "LEARN_MORE"
    SHOP_NOW = "SHOP_NOW"
    SIGN_UP = "SIGN_UP"
    DOWNLOAD = "DOWNLOAD"
    GET_QUOTE = "GET_QUOTE"
    CONTACT_US = "CONTACT_US"
    BOOK_NOW = "BOOK_NOW"
    APPLY_NOW = "APPLY_NOW"
    NO_BUTTON = "NO_BUTTON"


class FBAdsCSVGenerator:
    """
    Complete Facebook Ads CSV generator with all API fields
    """
    
    # Complete field mapping
    CAMPAIGN_FIELDS = [
        "Campaign Name",
        "Campaign Objective",
        "Buying Type",
        "Campaign Status",
        "Campaign Budget Optimization",
        "Campaign Budget",
        "Campaign Bid Strategy",
        "Campaign Spend Limit",
    ]
    
    AD_SET_FIELDS = [
        "Ad Set Name",
        "Optimization Goal",
        "Billing Event",
        "Bid Strategy",
        "Bid Amount",
        "Daily Budget",
        "Lifetime Budget",
        "Start Date",
        "End Date",
        "Ad Set Status",
        "Targeting Age Min",
        "Targeting Age Max",
        "Targeting Gender",
        "Targeting Locations",
        "Targeting Custom Audiences",
        "Targeting Excluded Custom Audiences",
        "Targeting Interests",
        "Targeting Behaviors",
        "Targeting Languages",
        "Placements",
        "Platform Positions",
        "Optimization Window",
        "Attribution Setting",
        "Conversion Window",
        "Promoted Object Pixel ID",
        "Promoted Object Custom Event Type",
        "Destination Type",
    ]
    
    AD_FIELDS = [
        "Ad Name",
        "Ad Status",
        "Body",  # Primary text
        "Title",  # Headline
        "Caption",  # Link description
        "Link",  # Destination URL
        "Call To Action",
        "Image Hash",  # For existing images
        "Image File",  # For new uploads
        "Video ID",  # For existing videos
        "Video File",  # For new uploads
        "Website URL",  # Can be different from Link
        "Display Link",  # vanity URL shown
        "UTM Source",
        "UTM Medium",
        "UTM Campaign",
        "UTM Term",
        "UTM Content",
        "Dynamic Creative",
        "Additional Body 1",
        "Additional Body 2",
        "Additional Body 3",
        "Additional Title 1",
        "Additional Title 2",
        "Additional Title 3",
        "Additional Image 1",
        "Additional Image 2",
        "Use Page Post",
        "Page Post ID",
        "Instagram Actor ID",
        "Facebook Page ID",
    ]
    
    # Carousel specific
    CAROUSEL_FIELDS = [
        "Carousel Card 1 Title",
        "Carousel Card 1 Body",
        "Carousel Card 1 Link",
        "Carousel Card 1 Image",
        "Carousel Card 2 Title",
        "Carousel Card 2 Body",
        "Carousel Card 2 Link",
        "Carousel Card 2 Image",
        # ... up to 10 cards
    ]
    
    # Multi-language DLO
    MULTI_LANGUAGE_FIELDS = [
        "Language 1 Code",
        "Language 1 Body",
        "Language 1 Title",
        "Language 1 Link",
        "Language 2 Code",
        "Language 2 Body",
        "Language 2 Title",
        "Language 2 Link",
    ]
    
    # Partnership ads
    PARTNERSHIP_FIELDS = [
        "Partnership Ad Code",
        "Creator Account ID",
    ]
    
    ALL_FIELDS = (
        CAMPAIGN_FIELDS + 
        AD_SET_FIELDS + 
        AD_FIELDS + 
        CAROUSEL_FIELDS[:8] +  # Include first 2 carousel cards
        MULTI_LANGUAGE_FIELDS[:8] +  # Include 2 languages
        PARTNERSHIP_FIELDS
    )
    
    @staticmethod
    def validate_date(date_str: str) -> bool:
        """Validate date format (YYYY-MM-DD)"""
        try:
            datetime.datetime.strptime(date_str, "%Y-%m-%d")
            return True
        except ValueError:
            return False
    
    @staticmethod
    def validate_budget(budget: str) -> bool:
        """Validate budget is a positive number"""
        try:
            return float(budget) > 0
        except ValueError:
            return False
    
    @staticmethod
    def validate_age(age: str) -> bool:
        """Validate age is between 13-65+"""
        try:
            age_int = int(age)
            return 13 <= age_int <= 65
        except ValueError:
            return age == "65+"
    
    def generate_traffic_campaign(
        self,
        campaign_name: str,
        ad_set_name: str,
        ad_name: str,
        daily_budget: float,
        target_url: str,
        ad_copy: Dict[str, str],
        image_file: str = None,
        image_hash: str = None
    ) -> List[Dict]:
        """
        Generate a complete traffic campaign CSV row
        
        Args:
            campaign_name: Name of the campaign
            ad_set_name: Name of the ad set
            ad_name: Name of the ad
            daily_budget: Daily budget in dollars
            target_url: Landing page URL
            ad_copy: Dict with 'body', 'title', 'caption'
            image_file: Filename for new image upload
            image_hash: Hash for existing image in library
        
        Returns:
            List of row dictionaries ready for CSV
        """
        
        row = {
            # Campaign Level
            "Campaign Name": campaign_name,
            "Campaign Objective": CampaignObjective.OUTCOME_TRAFFIC.value,
            "Buying Type": "AUCTION",
            "Campaign Status": "ACTIVE",
            "Campaign Budget Optimization": "FALSE",
            "Campaign Budget": "",
            "Campaign Bid Strategy": "LOWEST_COST_WITHOUT_CAP",
            "Campaign Spend Limit": "",
            
            # Ad Set Level
            "Ad Set Name": ad_set_name,
            "Optimization Goal": OptimizationGoal.LINK_CLICKS.value,
            "Billing Event": BillingEvent.LINK_CLICKS.value,
            "Bid Strategy": "LOWEST_COST_WITHOUT_CAP",
            "Bid Amount": "",
            "Daily Budget": str(daily_budget),
            "Lifetime Budget": "",
            "Start Date": datetime.datetime.now().strftime("%Y-%m-%d"),
            "End Date": "",
            "Ad Set Status": "ACTIVE",
            "Targeting Age Min": "18",
            "Targeting Age Max": "65+",
            "Targeting Gender": "All",
            "Targeting Locations": "United States",
            "Targeting Custom Audiences": "",
            "Targeting Excluded Custom Audiences": "",
            "Targeting Interests": "",
            "Targeting Behaviors": "",
            "Targeting Languages": "en",
            "Placements": "Automatic",
            "Platform Positions": "Facebook,Instagram",
            "Optimization Window": "1_DAY",
            "Attribution Setting": "7_DAY_CLICK_1_DAY_VIEW",
            "Conversion Window": "",
            "Promoted Object Pixel ID": "",
            "Promoted Object Custom Event Type": "",
            "Destination Type": "WEBSITE",
            
            # Ad Level
            "Ad Name": ad_name,
            "Ad Status": "ACTIVE",
            "Body": ad_copy.get('body', ''),
            "Title": ad_copy.get('title', ''),
            "Caption": ad_copy.get('caption', ''),
            "Link": target_url,
            "Call To Action": CallToAction.LEARN_MORE.value,
            "Image Hash": image_hash or "",
            "Image File": image_file or "",
            "Video ID": "",
            "Video File": "",
            "Website URL": target_url,
            "Display Link": "",
            "UTM Source": "facebook",
            "UTM Medium": "paid_social",
            "UTM Campaign": campaign_name.lower().replace(" ", "_"),
            "UTM Term": "",
            "UTM Content": ad_name.lower().replace(" ", "_"),
            "Dynamic Creative": "FALSE",
            "Additional Body 1": "",
            "Additional Body 2": "",
            "Additional Body 3": "",
            "Additional Title 1": "",
            "Additional Title 2": "",
            "Additional Title 3": "",
            "Additional Image 1": "",
            "Additional Image 2": "",
            "Use Page Post": "FALSE",
            "Page Post ID": "",
            "Instagram Actor ID": "",
            "Facebook Page ID": "",
            
            # Carousel (empty for single image)
            "Carousel Card 1 Title": "",
            "Carousel Card 1 Body": "",
            "Carousel Card 1 Link": "",
            "Carousel Card 1 Image": "",
            "Carousel Card 2 Title": "",
            "Carousel Card 2 Body": "",
            "Carousel Card 2 Link": "",
            "Carousel Card 2 Image": "",
            
            # Multi-language (empty for single language)
            "Language 1 Code": "",
            "Language 1 Body": "",
            "Language 1 Title": "",
            "Language 1 Link": "",
            "Language 2 Code": "",
            "Language 2 Body": "",
            "Language 2 Title": "",
            "Language 2 Link": "",
            
            # Partnership (empty)
            "Partnership Ad Code": "",
            "Creator Account ID": "",
        }
        
        return [row]
    
    def write_csv(self, rows: List[Dict], filename: str):
        """Write rows to CSV file"""
        with open(filename, 'w', newline='', encoding='utf-8') as f:
            writer = csv.DictWriter(f, fieldnames=self.ALL_FIELDS)
            writer.writeheader()
            writer.writerows(rows)
        print(f"✅ CSV generated: {filename}")
        print(f"   Rows: {len(rows)}")
        print(f"   Fields: {len(self.ALL_FIELDS)}")


# Example usage
if __name__ == "__main__":
    generator = FBAdsCSVGenerator()
    
    # Generate a sample campaign for Jake's brand
    campaign_rows = generator.generate_traffic_campaign(
        campaign_name="OpenClaw Launch Campaign",
        ad_set_name="Cold Traffic - Tech Enthusiasts",
        ad_name="OpenClaw Hero Ad v1",
        daily_budget=50.00,
        target_url="https://openclaw.com/?utm_source=facebook&utm_medium=paid_social",
        ad_copy={
            'body': "Meet OpenClaw: The AI assistant that actually gets stuff done. No prompts, no hand-holding. Just tell it what you want and watch it work. Join 10,000+ users automating their workflows.",
            'title': "OpenClaw - AI That Actually Works",
            'caption': "Start Your Free Trial Today"
        },
        image_file="openclaw_hero_1080x1080.jpg"
    )
    
    # Write to CSV
    output_file = "facebook_ads_bulk_upload.csv"
    generator.write_csv(campaign_rows, output_file)
    
    print("\n📋 Next Steps:")
    print("1. Upload your creative (openclaw_hero_1080x1080.jpg) to your computer")
    print("2. Go to Meta Ads Manager")
    print("3. Click the ⋮ menu > Import & Export > Import Ads")
    print(f"4. Upload {output_file}")
    print("5. Upload your creative file when prompted")
    print("6. Review and publish!")
    
    print("\n🎯 Field Validation Rules:")
    print("- Campaign Status: ACTIVE or PAUSED")
    print("- Dates: YYYY-MM-DD format")
    print("- Budget: Positive numbers only (no $ symbol)")
    print("- Age: 13-65 or '65+'")
    print("- Gender: All, Male, or Female")
    print("- Image Hash: Get from existing library or leave blank for new upload")
    print("- UTM parameters: Auto-generated for tracking")
    
    print("\n💡 Pro Tips:")
    print("- For multiple ads: duplicate the row and change Ad Name + creative")
    print("- For carousel: fill Carousel Card 1-10 fields")
    print("- For DLO: fill Language 1-5 Code/Body/Title/Link fields")
    print("- For dynamic creative: set Dynamic Creative=TRUE and fill Additional fields")
