"""
Cross-Channel Conversion Optimization (CCCO) Tools for Meta Ads MCP Server

This module provides tools for creating campaigns that optimize conversions
across both app and web channels using the omnichannel_object.

Based on Meta Marketing API v24.0:
https://developers.facebook.com/docs/ccco
"""

from __future__ import annotations

from typing import Dict, Any, Optional

from .errors import MetaApiError
from .logging import get_logger
from .meta_client import MetaClient
from .schemas import ToolResult

logger = get_logger(__name__)


class CCCOEngine:
    """Handles Cross-Channel Conversion Optimization operations"""
    
    def __init__(self, client: MetaClient):
        self.client = client
    
    async def create_ccco_campaign(
        self, 
        arguments: Dict[str, Any]
    ) -> ToolResult:
        """
        Create a campaign optimized for cross-channel conversions.
        
        CCCO optimizes for conversions that happen on both your app and website,
        combining signals from both channels for better performance.
        
        Args:
            arguments: {
                "ad_account_id": "act_123",
                "campaign_name": "Cross-Channel Campaign",
                "daily_budget": 10000,
                "app_id": "456",
                "app_store_urls": ["https://play.google.com/...", "https://apps.apple.com/..."],
                "pixel_id": "789",
                "event_type": "PURCHASE"
            }
        
        Returns:
            ToolResult with campaign and ad set details
        """
        try:
            ad_account_id = arguments.get("ad_account_id")
            campaign_name = arguments.get("campaign_name")
            daily_budget = arguments.get("daily_budget")
            app_id = arguments.get("app_id")
            pixel_id = arguments.get("pixel_id")
            
            if not all([ad_account_id, campaign_name, daily_budget, app_id, pixel_id]):
                return ToolResult(
                    ok=False,
                    error={"message": "ad_account_id, campaign_name, daily_budget, app_id, and pixel_id are required"}
                )
            
            logger.info(f"Creating CCCO campaign: {campaign_name}")
            
            # Create campaign
            campaign_data = {
                "name": campaign_name,
                "objective": "OUTCOME_SALES",
                "status": "PAUSED",
                "special_ad_categories": []
            }
            
            campaign_response = await self.client.post(
                f"{ad_account_id}/campaigns",
                body=campaign_data
            )
            campaign_id = campaign_response.get("id")
            
            # Build omnichannel_object for CCCO
            event_type = arguments.get("event_type", "PURCHASE")
            app_store_urls = arguments.get("app_store_urls", [])
            
            omnichannel_object = {
                "app": [{
                    "application_id": app_id,
                    "custom_event_type": event_type,
                    "object_store_urls": app_store_urls
                }],
                "pixel": [{
                    "pixel_id": pixel_id,
                    "custom_event_type": event_type
                }]
            }
            
            # Add pixel_rule if provided (for custom conversions)
            if "pixel_rule" in arguments:
                omnichannel_object["pixel"][0]["pixel_rule"] = arguments["pixel_rule"]
            
            # Create ad set with omnichannel_object
            targeting = {
                "geo_locations": {
                    "countries": arguments.get("targeting_countries", ["US"])
                }
            }
            
            adset_data = {
                "name": f"{campaign_name} - CCCO AdSet",
                "campaign_id": campaign_id,
                "daily_budget": daily_budget,
                "billing_event": "IMPRESSIONS",
                "optimization_goal": "CONVERSIONS",
                "bid_strategy": arguments.get("bid_strategy", "LOWEST_COST_WITHOUT_CAP"),
                "targeting": targeting,
                "status": "PAUSED",
                "promoted_object": {
                    "omnichannel_object": omnichannel_object
                }
            }
            
            adset_response = await self.client.post(
                f"{ad_account_id}/adsets",
                body=adset_data
            )
            adset_id = adset_response.get("id")
            
            return ToolResult(
                ok=True,
                data={
                    "campaign_id": campaign_id,
                    "adset_id": adset_id,
                    "campaign_type": "CROSS_CHANNEL_CONVERSION_OPTIMIZATION",
                    "omnichannel_object": omnichannel_object,
                    "message": "CCCO campaign created successfully",
                    "benefits": [
                        "Unified optimization across app and web",
                        "Higher conversion volume through signal sharing",
                        "Better attribution across channels",
                        "Reduced CPAs through combined learning"
                    ],
                    "requirements": [
                        "App SDK must be installed and sending events",
                        "Pixel must be installed and firing events",
                        "Both must use the same event type (e.g., PURCHASE)",
                        "App store URLs must be properly configured"
                    ],
                    "next_steps": [
                        "Create ad creatives",
                        "Verify app and pixel events are flowing",
                        "Activate campaign when ready"
                    ]
                }
            )
            
        except MetaApiError as exc:
            logger.error("create_ccco_campaign_failed", **exc.to_dict())
            return ToolResult(ok=False, error=exc.to_dict())
        except Exception as exc:
            logger.error(f"create_ccco_campaign_error: {exc}")
            return ToolResult(ok=False, error={"message": str(exc)})
    
    async def create_ccco_adset(
        self, 
        arguments: Dict[str, Any]
    ) -> ToolResult:
        """
        Create an ad set with omnichannel_object for existing campaign.
        
        Args:
            arguments: {
                "ad_account_id": "act_123",
                "campaign_id": "456",
                "name": "CCCO Ad Set",
                "daily_budget": 10000,
                "app_config": {
                    "application_id": "789",
                    "event_type": "PURCHASE",
                    "object_store_urls": [...]
                },
                "pixel_config": {
                    "pixel_id": "321",
                    "event_type": "PURCHASE"
                },
                "targeting_countries": ["US", "CA"]
            }
        
        Returns:
            ToolResult with ad set details
        """
        try:
            ad_account_id = arguments.get("ad_account_id")
            campaign_id = arguments.get("campaign_id")
            name = arguments.get("name")
            daily_budget = arguments.get("daily_budget")
            app_config = arguments.get("app_config", {})
            pixel_config = arguments.get("pixel_config", {})
            
            if not all([ad_account_id, campaign_id, name, daily_budget]):
                return ToolResult(
                    ok=False,
                    error={"message": "ad_account_id, campaign_id, name, and daily_budget are required"}
                )
            
            if not app_config.get("application_id") or not pixel_config.get("pixel_id"):
                return ToolResult(
                    ok=False,
                    error={"message": "Both app_config.application_id and pixel_config.pixel_id are required for CCCO"}
                )
            
            logger.info(f"Creating CCCO ad set: {name}")
            
            # Build omnichannel_object
            omnichannel_object = {
                "app": [{
                    "application_id": app_config["application_id"],
                    "custom_event_type": app_config.get("event_type", "PURCHASE"),
                    "object_store_urls": app_config.get("object_store_urls", [])
                }],
                "pixel": [{
                    "pixel_id": pixel_config["pixel_id"],
                    "custom_event_type": pixel_config.get("event_type", "PURCHASE")
                }]
            }
            
            targeting = {
                "geo_locations": {
                    "countries": arguments.get("targeting_countries", ["US"])
                }
            }
            
            adset_data = {
                "name": name,
                "campaign_id": campaign_id,
                "daily_budget": daily_budget,
                "billing_event": "IMPRESSIONS",
                "optimization_goal": "CONVERSIONS",
                "bid_strategy": arguments.get("bid_strategy", "LOWEST_COST_WITHOUT_CAP"),
                "targeting": targeting,
                "status": "PAUSED",
                "promoted_object": {
                    "omnichannel_object": omnichannel_object
                }
            }
            
            response = await self.client.post(
                f"{ad_account_id}/adsets",
                body=adset_data
            )
            
            return ToolResult(
                ok=True,
                data={
                    "adset_id": response.get("id"),
                    "campaign_id": campaign_id,
                    "omnichannel_object": omnichannel_object,
                    "message": "CCCO ad set created successfully"
                }
            )
            
        except MetaApiError as exc:
            logger.error("create_ccco_adset_failed", **exc.to_dict())
            return ToolResult(ok=False, error=exc.to_dict())
        except Exception as exc:
            logger.error(f"create_ccco_adset_error: {exc}")
            return ToolResult(ok=False, error={"message": str(exc)})
    
    async def get_ccco_insights(
        self, 
        arguments: Dict[str, Any]
    ) -> ToolResult:
        """
        Get insights for CCCO campaigns with channel breakdown.
        
        Shows performance split between app and web conversions.
        
        Args:
            arguments: {
                "object_id": "campaign_id or adset_id",
                "time_range": {"since": "2024-01-01", "until": "2024-01-31"}
            }
        
        Returns:
            ToolResult with cross-channel insights
        """
        try:
            object_id = arguments.get("object_id")
            
            if not object_id:
                return ToolResult(
                    ok=False,
                    error={"message": "object_id is required"}
                )
            
            logger.info(f"Getting CCCO insights for {object_id}")
            
            params = {
                "fields": ",".join([
                    "impressions",
                    "clicks",
                    "spend",
                    "actions",
                    "action_values",
                    "cost_per_action_type",
                    "website_purchase_roas",
                    "mobile_app_purchase_roas"
                ]),
                "action_breakdowns": "action_destination"
            }
            
            if "time_range" in arguments:
                params["time_range"] = arguments["time_range"]
            
            response = await self.client.get(
                f"{object_id}/insights",
                params=params
            )
            
            data = response.get("data", [{}])[0] if response.get("data") else {}
            
            # Parse actions by destination (app vs web)
            actions = data.get("actions", [])
            app_conversions = [a for a in actions if "app" in a.get("action_destination", "").lower()]
            web_conversions = [a for a in actions if "website" in a.get("action_destination", "").lower()]
            
            return ToolResult(
                ok=True,
                data={
                    "object_id": object_id,
                    "summary": {
                        "impressions": data.get("impressions"),
                        "clicks": data.get("clicks"),
                        "spend": data.get("spend"),
                        "website_roas": data.get("website_purchase_roas"),
                        "app_roas": data.get("mobile_app_purchase_roas")
                    },
                    "channel_breakdown": {
                        "app_conversions": app_conversions,
                        "web_conversions": web_conversions
                    },
                    "all_actions": actions
                }
            )
            
        except MetaApiError as exc:
            logger.error("get_ccco_insights_failed", **exc.to_dict())
            return ToolResult(ok=False, error=exc.to_dict())
        except Exception as exc:
            logger.error(f"get_ccco_insights_error: {exc}")
            return ToolResult(ok=False, error={"message": str(exc)})
    
    async def validate_ccco_setup(
        self, 
        arguments: Dict[str, Any]
    ) -> ToolResult:
        """
        Validate that CCCO prerequisites are met.
        
        Checks that app SDK and pixel are properly configured with matching events.
        
        Args:
            arguments: {
                "ad_account_id": "act_123",
                "app_id": "456",
                "pixel_id": "789",
                "event_type": "PURCHASE"
            }
        
        Returns:
            ToolResult with validation results
        """
        try:
            ad_account_id = arguments.get("ad_account_id")
            app_id = arguments.get("app_id")
            pixel_id = arguments.get("pixel_id")
            event_type = arguments.get("event_type", "PURCHASE")
            
            if not all([ad_account_id, app_id, pixel_id]):
                return ToolResult(
                    ok=False,
                    error={"message": "ad_account_id, app_id, and pixel_id are required"}
                )
            
            logger.info(f"Validating CCCO setup for app {app_id} and pixel {pixel_id}")
            
            validation_results = {
                "app_check": {"status": "PENDING"},
                "pixel_check": {"status": "PENDING"},
                "event_match": {"status": "PENDING"}
            }
            
            # Check app configuration
            try:
                app_response = await self.client.get(
                    app_id,
                    params={"fields": "id,name,object_store_urls"}
                )
                validation_results["app_check"] = {
                    "status": "PASS" if app_response.get("id") else "FAIL",
                    "app_name": app_response.get("name"),
                    "object_store_urls": app_response.get("object_store_urls", [])
                }
            except Exception as e:
                validation_results["app_check"] = {
                    "status": "FAIL",
                    "error": str(e)
                }
            
            # Check pixel configuration
            try:
                pixel_response = await self.client.get(
                    pixel_id,
                    params={"fields": "id,name,is_unavailable"}
                )
                validation_results["pixel_check"] = {
                    "status": "PASS" if pixel_response.get("id") and not pixel_response.get("is_unavailable") else "FAIL",
                    "pixel_name": pixel_response.get("name"),
                    "is_available": not pixel_response.get("is_unavailable", True)
                }
            except Exception as e:
                validation_results["pixel_check"] = {
                    "status": "FAIL",
                    "error": str(e)
                }
            
            # Overall validation
            all_pass = all(
                v.get("status") == "PASS" 
                for v in validation_results.values() 
                if isinstance(v, dict)
            )
            
            return ToolResult(
                ok=True,
                data={
                    "ccco_ready": all_pass,
                    "validation_results": validation_results,
                    "event_type": event_type,
                    "recommendations": [
                        "Ensure app SDK is sending the target event",
                        "Verify pixel is firing the same event type",
                        "Configure object_store_urls if not set",
                        "Allow 24-48 hours of event data before launching"
                    ] if not all_pass else ["All checks passed - ready for CCCO"],
                    "supported_events": [
                        "PURCHASE",
                        "ADD_TO_CART",
                        "COMPLETE_REGISTRATION",
                        "LEAD",
                        "INITIATED_CHECKOUT"
                    ]
                }
            )
            
        except MetaApiError as exc:
            logger.error("validate_ccco_setup_failed", **exc.to_dict())
            return ToolResult(ok=False, error=exc.to_dict())
        except Exception as exc:
            logger.error(f"validate_ccco_setup_error: {exc}")
            return ToolResult(ok=False, error={"message": str(exc)})


_ccco_engine: Optional[CCCOEngine] = None


def get_ccco_engine() -> CCCOEngine:
    """Get the global CCCOEngine instance"""
    global _ccco_engine
    if _ccco_engine is None:
        from .meta_client import get_client
        _ccco_engine = CCCOEngine(get_client())
    return _ccco_engine
