package kz.konturai.parser.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import kz.konturai.parser.model.CampaignPrediction;
import kz.konturai.parser.model.TargetingCampaign;
import kz.konturai.parser.repository.CampaignPredictionRepository;
import kz.konturai.parser.repository.TargetingCampaignRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
@RequiredArgsConstructor
@Slf4j
public class CampaignPredictionService {

    private final OpenAIAnalyticsService openAiService;
    private final CampaignPredictionRepository predictionRepository;
    private final TargetingCampaignRepository campaignRepository;
    private final ObjectMapper objectMapper;

    private static final String SYSTEM_PROMPT = """
            Ты эксперт по performance-маркетингу с 15-летним опытом в Meta Ads и TikTok Ads
            для рынка Казахстана и СНГ.

            На вход получаешь данные рекламной кампании. Твоя задача —
            предсказать результаты кампании и дать конкретные рекомендации.
            Отвечай ТОЛЬКО валидным JSON без markdown и без пояснений.

            Верни строго такую структуру:
            {
              "predictionScore": число от 0 до 100,
              "predictionLabel": "Отличная" | "Хорошая" | "Средняя" | "Слабая",
              "confidence": число от 0 до 100,
              "predictedMetrics": {
                "ctr": { "min": число, "max": число, "unit": "%" },
                "cpl": { "min": число, "max": число, "unit": "KZT" },
                "reach": { "min": число, "max": число, "unit": "человек" },
                "conversions": { "min": число, "max": число, "unit": "лидов" },
                "roas": { "min": число, "max": число, "unit": "x" }
              },
              "weeklyForecast": [
                { "week": 1, "expectedSpend": число, "expectedLeads": число, "expectedReach": число, "phase": "название" },
                { "week": 2, "expectedSpend": число, "expectedLeads": число, "expectedReach": число, "phase": "название" },
                { "week": 3, "expectedSpend": число, "expectedLeads": число, "expectedReach": число, "phase": "название" },
                { "week": 4, "expectedSpend": число, "expectedLeads": число, "expectedReach": число, "phase": "название" }
              ],
              "strengthFactors": ["фактор 1", "фактор 2", "фактор 3"],
              "riskFactors": ["риск 1", "риск 2"],
              "topRecommendations": [
                {
                  "priority": "HIGH",
                  "category": "CREATIVE",
                  "title": "заголовок",
                  "description": "детали",
                  "expectedImpact": "эффект"
                }
              ],
              "audienceInsights": {
                "bestPerformingSegment": "описание",
                "recommendedExpansion": "куда расширить",
                "exclusionAdvice": "кого исключить"
              },
              "budgetOptimization": {
                "currentAllocation": "описание",
                "recommendedReallocation": "куда перераспределить",
                "potentialCplReduction": "на сколько %"
              },
              "competitiveAnalysis": {
                "marketSaturation": "HIGH" | "MEDIUM" | "LOW",
                "differentiationScore": число от 0 до 100,
                "competitiveAdvantages": ["преимущество 1", "преимущество 2"]
              }
            }
            """;

    /**
     * Генерирует предсказание для кампании и сохраняет в MongoDB.
     */
    public CampaignPrediction generateAndSave(TargetingCampaign campaign) {
        log.info("[Prediction] Генерация предсказания для кампании {}", campaign.getId());

        String userMessage = buildUserMessage(campaign);

        try {
            String rawJson = openAiService.generateWithInstructionWithModel(
                    "",
                    userMessage,
                    "ru",
                    "gpt-4o",
                    SYSTEM_PROMPT,
                    4000,
                    120000L
            );
            CampaignPrediction prediction = parsePrediction(rawJson, campaign.getId());

            // Снимаем флаг isLatest со старых предсказаний
            predictionRepository.findByCampaignIdAndIsLatestTrue(campaign.getId())
                    .ifPresent(old -> {
                        old.setLatest(false);
                        predictionRepository.save(old);
                    });

            predictionRepository.save(prediction);
            log.info("[Prediction] Предсказание сохранено. Score: {}, Label: {}",
                    prediction.getPredictionScore(), prediction.getPredictionLabel());
            return prediction;

        } catch (Exception e) {
            log.error("[Prediction] Ошибка OpenAI API: {}", e.getMessage());
            throw new RuntimeException("Ошибка генерации предсказания: " + e.getMessage(), e);
        }
    }

    @Async("targetingExecutor")
    public void generateAsync(TargetingCampaign campaign) {
        try {
            generateAndSave(campaign);
        } catch (Exception e) {
            log.error("[Prediction] Ошибка асинхронной генерации для {}: {}", campaign.getId(), e.getMessage());
        }
    }

    public Optional<CampaignPrediction> getLatest(String campaignId) {
        return predictionRepository.findByCampaignIdAndIsLatestTrue(campaignId);
    }

    /** Пересчёт предсказаний каждый день в 06:00 для всех активных кампаний */
    @Scheduled(cron = "0 0 6 * * *")
    public void scheduledRecalculation() {
        log.info("[Prediction] Запуск планового пересчёта предсказаний");
        List<TargetingCampaign> active = campaignRepository.findAllByStatusAndUpdatedAtBefore(
                "active", LocalDateTime.now());
        for (TargetingCampaign campaign : active) {
            try {
                generateAndSave(campaign);
            } catch (Exception e) {
                log.error("[Prediction] Ошибка пересчёта для {}: {}", campaign.getId(), e.getMessage());
            }
        }
    }

    private String buildUserMessage(TargetingCampaign campaign) {
        StringBuilder sb = new StringBuilder();
        sb.append("ДАННЫЕ КАМПАНИИ:\n");

        if (campaign.getAiRecommendations() != null) {
            sb.append("Ниша: ").append(campaign.getAiRecommendations().getBusinessNiche()).append("\n");
            sb.append("Продукт: ").append(campaign.getAiRecommendations().getProductName()).append("\n");
            sb.append("Цель: ").append(campaign.getAiRecommendations().getGoal()).append("\n");
            sb.append("Тип таргетинга: ").append(campaign.getAiRecommendations().getRecommendedTargetingTypeLabel()).append("\n");
        }

        if (campaign.getBudget() != null) {
            sb.append("Бюджет: ").append(campaign.getBudget().getTotalBudget())
              .append(" ").append(campaign.getBudget().getCurrency()).append("\n");
            sb.append("Дневной бюджет: ").append(campaign.getBudget().getDailyBudget()).append("\n");
            sb.append("Дата начала: ").append(campaign.getBudget().getStartDate()).append("\n");
            sb.append("Дата окончания: ").append(campaign.getBudget().getEndDate()).append("\n");
        }

        if (campaign.getPlatforms() != null) {
            sb.append("Платформы: ").append(campaign.getPlatforms()).append("\n");
        }

        if (campaign.getAudience() != null) {
            sb.append("Аудитория: возраст ").append(campaign.getAudience().getAgeMin())
              .append("-").append(campaign.getAudience().getAgeMax()).append("\n");
            sb.append("Интересы: ").append(campaign.getAudience().getInterests()).append("\n");
            sb.append("Гео: ").append(campaign.getAudience().getLocations()).append("\n");
        }

        if (campaign.getAiRecommendations() != null &&
                campaign.getAiRecommendations().getTargetingRecommendation() != null) {
            var rec = campaign.getAiRecommendations().getTargetingRecommendation();
            sb.append("Фазы стратегии: ").append(rec.getPhases()).append("\n");
            sb.append("Конкурентный контекст: ").append(rec.getCompetitiveContext()).append("\n");
            sb.append("CII: ").append(rec.getCiiLevel()).append("\n");
        }

        if (campaign.getPerformanceMetrics() != null && campaign.getPerformanceMetrics().isDataAvailable()) {
            var m = campaign.getPerformanceMetrics();
            sb.append("ТЕКУЩИЕ МЕТРИКИ:\n");
            sb.append("CTR: ").append(m.getCtr()).append("%\n");
            sb.append("CPC: ").append(m.getCpc()).append(" KZT\n");
            sb.append("Охват: ").append(m.getReach()).append("\n");
            sb.append("Лиды: ").append(m.getLeads()).append("\n");
            sb.append("Потрачено: ").append(m.getSpend()).append(" ").append(m.getCurrency()).append("\n");
        }

        sb.append("Длительность кампании: ").append(campaign.getDurationDays()).append(" дней\n");
        sb.append("Статус: ").append(campaign.getStatus()).append("\n");

        return sb.toString();
    }

    private CampaignPrediction parsePrediction(String rawJson, String campaignId) {
        try {
            // Убираем markdown-обёртку
            String json = rawJson.trim();
            if (json.startsWith("```")) {
                int start = json.indexOf('\n');
                int end = json.lastIndexOf("```");
                if (start >= 0 && end > start) json = json.substring(start + 1, end).trim();
            }

            JsonNode root = objectMapper.readTree(json);

            // Парсим predictedMetrics
            Map<String, CampaignPrediction.MetricRange> metrics = null;
            if (root.has("predictedMetrics")) {
                metrics = objectMapper.convertValue(root.get("predictedMetrics"),
                        new TypeReference<>() {});
            }

            // Парсим weeklyForecast
            List<CampaignPrediction.WeeklyForecast> forecast = null;
            if (root.has("weeklyForecast")) {
                forecast = objectMapper.convertValue(root.get("weeklyForecast"),
                        new TypeReference<>() {});
            }

            // Парсим topRecommendations
            List<CampaignPrediction.Recommendation> recs = null;
            if (root.has("topRecommendations")) {
                recs = objectMapper.convertValue(root.get("topRecommendations"),
                        new TypeReference<>() {});
            }

            return CampaignPrediction.builder()
                    .campaignId(campaignId)
                    .createdAt(LocalDateTime.now())
                    .isLatest(true)
                    .predictionScore(root.path("predictionScore").asInt(0))
                    .predictionLabel(root.path("predictionLabel").asText("Средняя"))
                    .confidence(root.path("confidence").asInt(50))
                    .predictedMetrics(metrics)
                    .weeklyForecast(forecast)
                    .strengthFactors(objectMapper.convertValue(root.path("strengthFactors"), new TypeReference<>() {}))
                    .riskFactors(objectMapper.convertValue(root.path("riskFactors"), new TypeReference<>() {}))
                    .topRecommendations(recs)
                    .audienceInsights(objectMapper.convertValue(root.path("audienceInsights"),
                            CampaignPrediction.AudienceInsights.class))
                    .budgetOptimization(objectMapper.convertValue(root.path("budgetOptimization"),
                            CampaignPrediction.BudgetOptimizationInsights.class))
                    .competitiveAnalysis(objectMapper.convertValue(root.path("competitiveAnalysis"),
                            CampaignPrediction.CompetitiveAnalysis.class))
                    .build();

        } catch (Exception e) {
            log.error("[Prediction] Ошибка парсинга ответа Claude: {}", e.getMessage());
            // Возвращаем минимальный объект чтобы не потерять кампанию
            return CampaignPrediction.builder()
                    .campaignId(campaignId)
                    .createdAt(LocalDateTime.now())
                    .isLatest(true)
                    .predictionScore(50)
                    .predictionLabel("Средняя")
                    .confidence(30)
                    .build();
        }
    }
}
