package kz.konturai.parser.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import kz.konturai.parser.dto.targeting.TargetingOrchestrationDto;
import kz.konturai.parser.model.MarketingAnalysisV3Document;
import kz.konturai.parser.model.MarketingStrategy;
import kz.konturai.parser.model.SocialMediaCredentials;
import kz.konturai.parser.model.TargetingCampaign;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
@Slf4j
public class AiTargetologistService {

    private final OpenAIAnalyticsService openAiService;
    private final ObjectMapper objectMapper;

    /**
     * Executes the "Antigravity" Orchestration Pipeline.
     * Maps business metrics, strategy data, and ready-made media assets into a strictly validated JSON payload.
     *
     * @param campaign The current campaign context (budget, goals, platforms).
     * @param analysis The underlying strategy analysis (audiences, triggers, market).
     * @param strategy The content strategy housing ready-made texts and media.
     * @param credentials Ad Account credentials (to pass platform/ad-account IDs context).
     * @return Fully populated JSON Orchestration DTO.
     */
    public TargetingOrchestrationDto orchestrateCampaign(
            TargetingCampaign campaign,
            MarketingAnalysisV3Document analysis,
            MarketingStrategy strategy,
            List<SocialMediaCredentials> credentials) {
            
        log.info("[Antigravity Pipeline] Starting orchestration for campaign {}, analysisId: {}", campaign.getId(), analysis.getId());
        
        try {
            String systemPrompt = buildSystemMandate();
            String userPrompt = buildOrchestratorContext(campaign, analysis, strategy, credentials);
            
            // Generate through strict OpenAI call.
            // Notice: requesting max length for complex JSON tree, timeout scaled to 180s.
            log.info("[Antigravity Pipeline] Sending context to Neural API...");
            String rawJsonResponse = openAiService.generateWithInstructionWithModel(
                    "", // text/context is baked into userPrompt
                    userPrompt,
                    "ru",
                    "gpt-4o", // High capability model required for strict JSON compliance and deep logic
                    systemPrompt,
                    15000, 
                    180000L
            );

            if (rawJsonResponse == null || rawJsonResponse.isBlank()) {
                throw new IllegalStateException("OpenAI returned empty orchestration payload");
            }

            // Cleanup potential markdown blocks if the model hallucinates them despite system prompt
            String cleanJson = rawJsonResponse.replaceAll("(?s)^```json\\s*", "").replaceAll("(?s)\\s*```$", "").trim();
            log.debug("[Antigravity] Raw Orchestration JSON: {}", cleanJson);
            
            // Robust specific mapper
            ObjectMapper strictMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            
            TargetingOrchestrationDto orchestration = strictMapper.readValue(cleanJson, TargetingOrchestrationDto.class);
            log.info("[Antigravity Pipeline] Successfully parsed TargetingOrchestrationDto. Orchestration ID: {}", orchestration.getOrchestrationId());
            
            return orchestration;

        } catch (Exception e) {
            log.error("[Antigravity Pipeline] CRITICAL FAILURE during orchestration: {}", e.getMessage(), e);
            throw new RuntimeException("AI Targeting Orchestration failed: " + e.getMessage(), e);
        }
    }

    private String buildSystemMandate() {
        return """
            SYSTEM ROLE & ARCHITECTURE MANDATE
            You are "Antigravity", an enterprise-grade AI Targeting Orchestrator and Media Buying Architect. Your sole function is to process sanitized marketing strategies and ready-made media assets, compiling them into a highly structured, production-ready payload for Ads Platform APIs (Meta Graph API, Google Ads API, TikTok Marketing API).

            You DO NOT generate basic raw creatives from scratch if ready-made texts exist. You DO NOT alter the core strategy. You map inputs to rigid targeting parameters, establish A/B testing matrices, calculate budget pacing, and define algorithmic optimization rules.

            CRITICAL BUDGET RULE:
            The input context contains "campaign_daily_budget_usd_approx" and "campaign_total_budget_usd_approx". You MUST use EXACTLY these values for all budget fields in the output JSON (daily_budget_usd, campaign_daily_budget_usd). Distribute total budget proportionally across adsets but NEVER exceed the total. Do NOT invent or inflate budget numbers.

            OUTPUT CONTRACT:
            Your output must be EXCLUSIVELY a valid JSON object. DO NOT wrap it in markdown block quotes. DO NOT include any natural language explanation, introductory text, or concluding remarks. Just raw valid JSON.
            The JSON keys must be strictly snake_case conforming to the supplied schema structure.
            """;
    }

    private String buildOrchestratorContext(
            TargetingCampaign campaign, 
            MarketingAnalysisV3Document analysis, 
            MarketingStrategy strategy,
            List<SocialMediaCredentials> credentials) throws JsonProcessingException {
            
        // 1. Business Metrics Context
        double totalKzt = campaign.getBudget() != null && campaign.getBudget().getTotalBudget() != null
                ? campaign.getBudget().getTotalBudget() : 0.0;
        double dailyKzt = campaign.getBudget() != null && campaign.getBudget().getDailyBudget() != null
                ? campaign.getBudget().getDailyBudget() : (totalKzt / 30.0);
        // KZT to USD approximate rate for AI context (1 USD ~ 470 KZT)
        double totalUsd = Math.round(totalKzt / 470.0 * 100.0) / 100.0;
        double dailyUsd = Math.round(dailyKzt / 470.0 * 100.0) / 100.0;

        Map<String, Object> businessMetrics = new HashMap<>();
        businessMetrics.put("target_objective", campaign.getObjective() != null ? campaign.getObjective().name() : "TRAFFIC");
        businessMetrics.put("campaign_daily_budget_kzt", dailyKzt);
        businessMetrics.put("campaign_total_budget_kzt", totalKzt);
        businessMetrics.put("campaign_daily_budget_usd_approx", dailyUsd);
        businessMetrics.put("campaign_total_budget_usd_approx", totalUsd);
        businessMetrics.put("budget_currency_note", "IMPORTANT: All budget fields in output JSON (daily_budget_usd, campaign_daily_budget_usd) MUST use the USD amounts provided above. Do NOT invent new budget amounts.");
        businessMetrics.put("target_platforms", campaign.getPlatforms());
        
        // 2. Extracted Media Assets (Texts with hashtags)
        List<MarketingStrategy.PostCalendarItem> mediaAssets = strategy.getPostCalendar() != null ? strategy.getPostCalendar() : List.of();
        
        StringBuilder prompt = new StringBuilder();
        prompt.append("INPUT CONTEXT (READ-ONLY):\n");
        prompt.append("1. \"business_metrics\": ").append(objectMapper.writeValueAsString(businessMetrics)).append("\n\n");
        prompt.append("2. \"strategy_matrix\": ").append(objectMapper.writeValueAsString(analysis.getResultData())).append("\n\n");
        prompt.append("3. \"media_assets\": ").append(objectMapper.writeValueAsString(mediaAssets)).append("\n\n");
        
        prompt.append("""
            EXECUTION PROTOCOL
            
            PHASE 1: CAMPAIGN TOPOLOGY & NAMING CONVENTION
            1. Enforce strict naming conventions for parsing: [Platform]_[Objective]_[Geo]_[Date]_[UniqueIdentifier].
            2. Determine Campaign Budget Optimization (CBO) vs. AdSet Budget Optimization (ABO) based on the number of audiences. Use ABO for strict A/B testing of specific segments; use CBO for scaling proven assets.
            3. Isolate variables. Never test more than one major variable (e.g., audience, creative format) per AdSet.
            
            PHASE 2: TARGETING ENGINE TRANSLATION
            Map the "strategy_matrix" to precise API-level targeting parameters. 
            1. Demographic Constraints: Calculate reasonable Min_Age, Max_Age based on the strategy.
            2. Detailed Targeting Matrix: Group interests logically. Select 2-4 HIGHLY relevant interests. 
            3. Placements: Optimize dynamically based on objective.
            
            PHASE 3: THE A/B TESTING & CREATIVE MAPPING
            1. Map "media_assets" (texts, images, video paths, hashtags) exactly into your ads. USE SPECIFICALLY THE post_text AND hashtags PROVIDED. DO NOT hallucinate new ad copy if it is provided there. Match the content theme to the targeting AdSet.
            2. Ensure every Ad has proper UTM tracking parameters appended to destination_url: utm_source={{site_source_name}}&utm_medium={{placement}}&utm_campaign={{campaign.name}}&utm_content={{ad.name}}.
            
            PHASE 4: BUDGET ALLOCATION & PACING ALGORITHM
            1. Allocate daily budget into the created AdSets intelligently based on total campaign budget.
            2. Set optimization goals correctly (e.g., OFFSITE_CONVERSIONS or LINK_CLICKS).
            
            PHASE 5: RULES ENGINE (MICRO-OPTIMIZATION PROTOCOL)
            Generate a strict set of logical conditions for the external cron-job/rules engine:
            1. EARLY_KILL: IF Spend > BudgetLimit AND actions < Threshold THEN Action = PAUSE.
            2. SCALE_UP: IF CPA < Target AND Frequency < 2.5 THEN Action = INCREASE_BUDGET.
            
            REQUIRED JSON SCHEMA STRUCTURE:
            {
              "orchestration_id": "uuid-v4",
              "platform_target": "META_ADS",
              "campaigns": [
                {
                  "campaign_name": "string",
                  "objective": "string",
                  "special_ad_categories": [],
                  "buying_type": "AUCTION",
                  "budget_strategy": { "is_cbo": false, "campaign_daily_budget_usd": 150.0 },
                  "adsets": [
                      {
                         "adset_name": "string",
                         "daily_budget_usd": 50.0,
                         "optimization_goal": "string",
                         "billing_event": "IMPRESSIONS",
                         "bid_strategy": "LOWEST_COST_WITHOUT_CAP",
                         "targeting": {
                            "geo_locations": { "countries": ["KZ"] },
                            "age_min": 18, "age_max": 65, "genders": [1],
                            "flexible_spec": [ { "interests": [{ "id": "123", "name": "InterestName" }] } ],
                            "exclusions": {},
                            "publisher_platforms": ["facebook", "instagram"],
                            "device_platforms": ["mobile"]
                         },
                         "ads": [
                            {
                               "ad_name": "string",
                               "creative_payload": {
                                  "asset_id": "Use image_filename or video_filename from media_assets here",
                                  "body_text_id": "Use EXACT post_text from media_assets here",
                                  "headline_id": "Use EXACT theme from media_assets here",
                                  "call_to_action": "LEARN_MORE",
                                  "destination_url": "https://example.com/url_with_utms"
                               }
                            }
                         ]
                      }
                  ]
                }
              ],
              "automation_rules": [
                 {
                    "rule_id": "string",
                    "entity_level": "ADSET",
                    "condition_group": "AND",
                    "conditions": [ {"metric": "spend", "operator": "GREATER_THAN", "value": 75.0} ],
                    "action": "PAUSE", "action_value": 0.0
                 }
              ]
            }
            """);

        return prompt.toString();
    }
}
