import os
from dotenv import load_dotenv
from facebook_business.api import FacebookAdsApi
from facebook_business.adobjects.adaccount import AdAccount
from facebook_business.adobjects.adset import AdSet
from facebook_business.adobjects.campaign import Campaign
from facebook_business.adobjects.ad import Ad
from facebook_business.exceptions import FacebookRequestError

import json

load_dotenv()
FacebookAdsApi.init(access_token=os.getenv("FB_ACCESS_TOKEN"))
AD_ACCOUNT_ID = os.getenv("AD_ACCOUNT_ID")  # act_857066298332756



def duplicate_ad(ad_id: str, dest_adset_id: str | None = None):
    src = Ad(ad_id).api_get(fields=[
        Ad.Field.name,
        Ad.Field.adset_id,
        Ad.Field.creative,  # contains {'id': '...'}
    ])

    creative = src.get(Ad.Field.creative) or {}
    creative_id = creative.get("id")
    if not creative_id:
        raise SystemExit("Source ad has no creative id; cannot duplicate with this simple method.")

    params = {
        Ad.Field.name: src[Ad.Field.name],
        "adset_id": dest_adset_id or src[Ad.Field.adset_id],
        "creative": {"creative_id": creative_id},  # reuse same creative
        Ad.Field.status: "PAUSED",  # start paused
    }

    created = AdAccount(AD_ACCOUNT_ID).create_ad(params=params)
    print("New ad id:", created[Ad.Field.id])
    return created[Ad.Field.id]

def duplicate_adset(adset_id: str, budget=None):
    # 1) Load source ad set
    src = AdSet(adset_id).api_get(fields=[
        AdSet.Field.name,
        AdSet.Field.campaign_id,
        AdSet.Field.daily_budget,
        AdSet.Field.billing_event,
        AdSet.Field.optimization_goal,
        AdSet.Field.bid_amount,
        AdSet.Field.targeting,
        AdSet.Field.promoted_object,
        "destination_type",
    ])

    # 🔧 Fix 1: make sure targeting and promoted_object are dicts (not strings)
    def to_dict(v):
        if isinstance(v, str):
            try:
                return json.loads(v)
            except Exception:
                return {}
        return dict(v or {})

    targeting = to_dict(src.get(AdSet.Field.targeting))
    promoted_object = to_dict(src.get(AdSet.Field.promoted_object))
    dest_type = src.get("destination_type") or "ON_AD"

    # 2) Create new ad set (PAUSED) with same settings
    params = {
        AdSet.Field.name: src[AdSet.Field.name],
        AdSet.Field.campaign_id: src[AdSet.Field.campaign_id],
        AdSet.Field.daily_budget: int(budget * 100) if budget is not None else src.get(AdSet.Field.daily_budget),
        AdSet.Field.billing_event: src[AdSet.Field.billing_event],
        AdSet.Field.optimization_goal: src[AdSet.Field.optimization_goal],
        AdSet.Field.targeting: targeting,
        AdSet.Field.status: "PAUSED",
        AdSet.Field.promoted_object: promoted_object,
        AdSet.Field.bid_strategy: AdSet.BidStrategy.lowest_cost_without_cap,
        "destination_type": dest_type,  # ✅ Fix 2: use source destination_type exactly
    }

    if src.get(AdSet.Field.bid_amount):
        params[AdSet.Field.bid_amount] = src.get(AdSet.Field.bid_amount)

    created_adset = AdAccount(AD_ACCOUNT_ID).create_ad_set(params=params)
    new_adset_id = created_adset[AdSet.Field.id]
    print("New ad set id:", new_adset_id)

    # 3) Duplicate all ads (reuse creatives)
    new_ad_ids = []
    ads = list(
        AdSet(adset_id).get_ads(
            fields=[Ad.Field.id, Ad.Field.name, Ad.Field.creative],
            params={"limit": 200, "effective_status": ["ACTIVE","PAUSED","ARCHIVED"]}
        )
    )
    for a in ads:
        creative = a.get(Ad.Field.creative) or {}
        creative_id = creative.get("id")
        if not creative_id:
            continue
        ad_params = {
            Ad.Field.name: a[Ad.Field.name],
            "adset_id": new_adset_id,
            "creative": {"creative_id": creative_id},
            Ad.Field.status: "PAUSED",
        }
        new_ad = AdAccount(AD_ACCOUNT_ID).create_ad(params=ad_params)
        new_ad_ids.append(new_ad[Ad.Field.id])

    print("New ad ids:", new_ad_ids)
    return new_adset_id, new_ad_ids

def duplicate_campaign(campaign_id: str):
    # 1) Read source campaign
    c = Campaign(campaign_id).api_get(fields=[
        Campaign.Field.name,
        Campaign.Field.objective,
        Campaign.Field.buying_type,
        Campaign.Field.special_ad_categories,
        Campaign.Field.special_ad_category_country,
        Campaign.Field.bid_strategy,
        "daily_budget",
        "lifetime_budget",
    ])
    is_cbo = bool(c.get("daily_budget") or c.get("lifetime_budget"))

    # 2) Create new campaign (PAUSED). Budgets/bid_strategy only for CBO.
    params = {
        Campaign.Field.name: c[Campaign.Field.name],
        Campaign.Field.objective: c.get(Campaign.Field.objective),
        Campaign.Field.buying_type: c.get(Campaign.Field.buying_type),
        Campaign.Field.special_ad_categories: c.get(Campaign.Field.special_ad_categories) or [],
        Campaign.Field.special_ad_category_country: c.get(Campaign.Field.special_ad_category_country) or [],
        Campaign.Field.status: "PAUSED",
    }
    if is_cbo:
        if c.get("daily_budget"):    params["daily_budget"] = c.get("daily_budget")
        if c.get("lifetime_budget"): params["lifetime_budget"] = c.get("lifetime_budget")
        if c.get(Campaign.Field.bid_strategy):
            params[Campaign.Field.bid_strategy] = c.get(Campaign.Field.bid_strategy)

    new_campaign = AdAccount(AD_ACCOUNT_ID).create_campaign(params=params)
    new_campaign_id = new_campaign[Campaign.Field.id]
    print("✔ New campaign:", new_campaign_id)

    # 3) Duplicate each ad set and retry on 2490487 by switching to LOWEST_COST_WITHOUT_CAP (no bid_amount)
    for s in Campaign(campaign_id).get_ad_sets(fields=[
        AdSet.Field.id,
        AdSet.Field.name,
        AdSet.Field.daily_budget,
        AdSet.Field.billing_event,
        AdSet.Field.optimization_goal,
        AdSet.Field.bid_amount,
        AdSet.Field.targeting,
        AdSet.Field.promoted_object,
        "destination_type",
        AdSet.Field.end_time,
    ], params={"limit": 200}):

        as_params = {
            AdSet.Field.name: s[AdSet.Field.name],
            AdSet.Field.campaign_id: new_campaign_id,
            AdSet.Field.daily_budget: s.get(AdSet.Field.daily_budget),
            AdSet.Field.billing_event: s.get(AdSet.Field.billing_event),
            AdSet.Field.optimization_goal: s.get(AdSet.Field.optimization_goal),
            AdSet.Field.targeting: dict(s.get(AdSet.Field.targeting) or {}),
            AdSet.Field.status: "PAUSED",
            AdSet.Field.promoted_object: dict(s.get(AdSet.Field.promoted_object) or {}),
            "destination_type": s.get("destination_type") or "ON_AD",
        }
        if s.get(AdSet.Field.bid_amount):
            as_params[AdSet.Field.bid_amount] = s.get(AdSet.Field.bid_amount)
        if s.get(AdSet.Field.end_time):
            as_params[AdSet.Field.end_time] = s.get(AdSet.Field.end_time)

        try:
            new_as = AdAccount(AD_ACCOUNT_ID).create_ad_set(params=as_params)
        except FacebookRequestError as e1:
            if "2490487" in str(e1):
                # Source has no bid and Meta demands one → switch to a strategy that doesn't need a bid.
                as_params.pop(AdSet.Field.bid_amount, None)
                as_params["bid_strategy"] = "LOWEST_COST_WITHOUT_CAP"  # a.k.a. “Largest volume”
                new_as = AdAccount(AD_ACCOUNT_ID).create_ad_set(params=as_params)
            else:
                raise

        new_adset_id = new_as[AdSet.Field.id]
        print("  ↳ New ad set:", new_adset_id)

        # 4) Duplicate ads (reuse creatives), start PAUSED
        for a in AdSet(s["id"]).get_ads(fields=[Ad.Field.name, Ad.Field.creative], params={"limit": 200}):
            creative_id = (a.get(Ad.Field.creative) or {}).get("id")
            if not creative_id:
                continue
            ad_params = {
                Ad.Field.name: a[Ad.Field.name],
                "adset_id": new_adset_id,
                "creative": {"creative_id": creative_id},
                Ad.Field.status: "PAUSED",
            }
            new_ad = AdAccount(AD_ACCOUNT_ID).create_ad(params=ad_params)
            print("    • New ad:", new_ad[Ad.Field.id])

    return new_campaign_id
