package kz.konturai.parser.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import kz.konturai.parser.config.TargetingApiConfig;
import kz.konturai.parser.dto.AudienceSegmentDto;
import kz.konturai.parser.exception.AudienceGenerationException;
import kz.konturai.parser.model.MarketingAnalysisV3Document;
import kz.konturai.parser.model.TargetingAudienceProfile;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Service
@RequiredArgsConstructor
@Slf4j
public class AudienceSegmentationService {

    private final OpenAIAnalyticsService openAiService;
    private final TargetingApiConfig apiConfig;
    private final ObjectMapper objectMapper;
    
    // In-memory cache instead of Redis to avoid external dependencies
    private final ConcurrentMap<String, String> cache = new ConcurrentHashMap<>();

    public List<AudienceSegmentDto> segmentAudience(MarketingAnalysisV3Document analysis) {
        String analysisId = analysis.getId();
        String cacheKey = "segments:" + analysisId;

        String cached = cache.get(cacheKey);
        if (cached != null) {
            try {
                return objectMapper.readValue(cached, new TypeReference<List<AudienceSegmentDto>>() {});
            } catch (JsonProcessingException e) {
                log.warn("Failed to parse cached segments, generating new ones...");
            }
        }

        try {
            String analysisJson = objectMapper.writeValueAsString(analysis.getResultData());
            String systemPrompt = "Ты — эксперт по аудиторному таргетингу с 15-летним опытом в digital-маркетинге на рынке Казахстана. " +
                    "На основе данных анализа создай МИНИМУМ 5 чётких сегментов аудитории. Верни только JSON-массив объектов без маркдауна. " +
                    "Для каждого сегмента верни:\n" +
                    "- segmentName: яркое название\n" +
                    "- description: детальное описание\n" +
                    "- ageMin, ageMax: числа\n" +
                    "- genders: массив строк (MALE, FEMALE)\n" +
                    "- incomeLevelKzt: оценка дохода\n" +
                    "- platform: основная платформа (INSTAGRAM, TIKTOK, FACEBOOK)\n" +
                    "- facebookInterests: массив строк\n" +
                    "- tiktokInterestCategories: массив строк\n" +
                    "- behaviors: массив строк\n" +
                    "- estimatedReachAlmaty: число\n" +
                    "- estimatedReachKazakhstan: число\n" +
                    "- recommendedMessage: ключевое сообщение\n" +
                    "- bestTimeToShow: строка времени\n" +
                    "- contentFormat: формат\n" +
                    "- estimatedCpmKzt: число\n" +
                    "- segmentScore: число (0-100)\n" +
                    "КОНТЕКСТ: " + analysisJson;

            String response = openAiService.generateWithInstructionWithModel(
                    "Создай сегменты аудитории.",
                    systemPrompt,
                    "ru",
                    apiConfig.getAi().getAudienceModel(),
                    systemPrompt,
                    apiConfig.getAi().getMaxAudienceTokens()
            );

            if (response == null || response.isBlank()) {
                throw new AudienceGenerationException("OpenAI returned null/empty response for segmentation");
            }
            
            // Clean markdown blocks if AI returned them
            if (response.startsWith("```json")) {
                response = response.substring(7, response.lastIndexOf("```")).trim();
            }

            List<AudienceSegmentDto> segments = objectMapper.readValue(response, new TypeReference<List<AudienceSegmentDto>>() {});
            segments.sort(Comparator.comparingInt(AudienceSegmentDto::getSegmentScore).reversed());

            cache.put(cacheKey, objectMapper.writeValueAsString(segments));
            return segments;

        } catch (Exception e) {
            log.error("Error generating audience segments", e);
            throw new AudienceGenerationException("Failed to segment audience", e);
        }
    }

    public TargetingAudienceProfile mergeSegmentsWithExistingAudience(List<AudienceSegmentDto> aiSegments, TargetingAudienceProfile manual) {
        if (manual == null) {
            manual = new TargetingAudienceProfile();
        }

        Set<String> mergedInterests = new HashSet<>(manual.getInterests() != null ? manual.getInterests() : Collections.emptyList());
        Set<String> mergedBehaviors = new HashSet<>(manual.getBehaviors() != null ? manual.getBehaviors() : Collections.emptyList());

        int minAge = manual.getAgeMin() > 0 ? manual.getAgeMin() : 18;
        int maxAge = manual.getAgeMax() > 0 ? manual.getAgeMax() : 65;

        for (AudienceSegmentDto seg : aiSegments) {
            if (seg.getFacebookInterests() != null) mergedInterests.addAll(seg.getFacebookInterests());
            if (seg.getBehaviors() != null) mergedBehaviors.addAll(seg.getBehaviors());
            if (seg.getAgeMin() < minAge && manual.getAgeMin() == 0) minAge = seg.getAgeMin();
            if (seg.getAgeMax() > maxAge && manual.getAgeMax() == 0) maxAge = seg.getAgeMax();
        }

        TargetingAudienceProfile result = TargetingAudienceProfile.builder()
                .ageMin(minAge)
                .ageMax(maxAge)
                .genders(manual.getGenders() != null ? manual.getGenders() : List.of("ALL"))
                .locations(manual.getLocations() != null ? manual.getLocations() : new ArrayList<>())
                .interests(new ArrayList<>(mergedInterests))
                .behaviors(new ArrayList<>(mergedBehaviors))
                .languages(manual.getLanguages() != null ? manual.getLanguages() : List.of("RU", "KK"))
                .customAudiences(manual.getCustomAudiences())
                .excludedAudiences(manual.getExcludedAudiences())
                .deviceTypes(manual.getDeviceTypes() != null ? manual.getDeviceTypes() : List.of("mobile"))
                .connectionType(manual.getConnectionType() != null ? manual.getConnectionType() : "ALL")
                .audienceScore(85) // Placeholder
                .build();
        return result;
    }

    public Map<String, Long> estimateAudienceSize(TargetingAudienceProfile profile, String platform) {
        long baseSize = switch (platform.toUpperCase()) {
            case "INSTAGRAM" -> 6500000L;
            case "TIKTOK" -> 8000000L;
            case "FACEBOOK" -> 4000000L;
            default -> 5000000L;
        };

        // Naive heuristic adjustment based on profile
        long minEstimated = (long) (baseSize * 0.1);
        long maxEstimated = (long) (baseSize * 0.4);

        profile.setEstimatedReachMin(minEstimated);
        profile.setEstimatedReachMax(maxEstimated);

        return Map.of(
                "estimated_min", minEstimated,
                "estimated_max", maxEstimated
        );
    }
}
