package kz.konturai.parser.service;

import kz.konturai.parser.model.MarketItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.core.ParameterizedTypeReference;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

import reactor.netty.http.client.HttpClient;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;

@Service
public class OllamaAnalyticsService {

    private static final Logger logger = LoggerFactory.getLogger(OllamaAnalyticsService.class);

    private final WebClient webClient;

    @Value("${ollama.model:gemma3:1b}")
    private String modelName;

    @Value("${ollama.timeoutMs:6000000}")
    private long timeoutMs;

    @Value("${ollama.connectTimeoutMs:10000000}")
    private int connectTimeoutMs;

    @Value("${ollama.responseTimeoutMs:60000000}")
    private long responseTimeoutMs;

    public OllamaAnalyticsService(@Value("${ollama.host:http://185.35.223.45:11434}") String ollamaHost) {
        HttpClient httpClient = HttpClient.create()
                .compress(true)
                .responseTimeout(Duration.ofMillis(responseTimeoutMs));

        this.webClient = WebClient.builder()
                .baseUrl(ollamaHost)
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .build();
    }

    public MarketItem.Analytics analyzeText(String text) {
        return analyzeText(text, "ru");
    }

    public MarketItem.Analytics analyzeText(String text, String language) {
        MarketItem.Analytics analytics = new MarketItem.Analytics();
        boolean isRussian = "ru".equalsIgnoreCase(language) || "russian".equalsIgnoreCase(language);

        try {
            String summaryPrompt = isRussian
                    ? "Напиши краткое саммари следующей новостной статьи на русском языке. Ответ должен содержать только саммари из 3-4 предложений, без лишних вступлений. Статья: "
                    : "Write a brief summary of the following news article in English. The response should contain only a summary of 3-4 sentences, without any unnecessary introductions. Article: ";
            String summary = generate(text, summaryPrompt);
            analytics.setSummary(summary);
        } catch (Exception e) {
            logger.warn("Failed to get summary from Ollama: {}", e.getMessage());
        }

        try {
            String tagsPrompt = isRussian
                    ? "Извлеки 5-7 ключевых слов или тегов из текста новостной статьи. В ответе дай только список тегов через запятую, без нумерации и заголовков. Статья: "
                    : "Extract 5-7 key words or tags from the news article text. In your response, provide only a list of tags separated by commas, without numbering or headers. Article: ";
            String tagsCsv = generate(text, tagsPrompt);
            String[] tags = tagsCsv == null ? new String[] {} : tagsCsv.replace("\n", " ").split("\\s*,\\s*");
            analytics.setTags(tags);
        } catch (Exception e) {
            logger.warn("Failed to get tags from Ollama: {}", e.getMessage());
        }

        try {
            String sentimentPrompt = isRussian
                    ? "Определи тональность текста новостной статьи. В ответе дай только одно слово латиницей: positive, negative или neutral. Статья: "
                    : "Determine the sentiment of the news article text. In your response, provide only one word in English: positive, negative, or neutral. Article: ";
            String sentiment = generate(text, sentimentPrompt);
            if (sentiment != null) {
                sentiment = sentiment.trim().toLowerCase();
            }
            analytics.setSentiment(sentiment);
        } catch (Exception e) {
            logger.warn("Failed to get sentiment from Ollama: {}", e.getMessage());
        }

        try {
            String entitiesPrompt = isRussian
                    ? "Извлеки из текста имена людей, названия компаний и географические локации. В ответе дай только JSON объект следующей структуры: {\\\"persons\\\": [], \\\"companies\\\": [], \\\"locations\\\": []}. Статья: "
                    : "Extract from the text names of people, company names, and geographic locations. In your response, provide only a JSON object with the following structure: {\\\"persons\\\": [], \\\"companies\\\": [], \\\"locations\\\": []}. Article: ";
            String entitiesJson = generate(text, entitiesPrompt);
            Map<String, Object> entities = new HashMap<>();
            if (entitiesJson != null && entitiesJson.trim().startsWith("{")) {
                try {
                    ObjectMapper mapper = new ObjectMapper();
                    entities = mapper.readValue(entitiesJson, new TypeReference<Map<String, Object>>() {
                    });
                } catch (Exception parseEx) {
                    entities.put("raw", entitiesJson);
                }
            }
            analytics.setEntities(entities);
        } catch (Exception e) {
            logger.warn("Failed to get entities from Ollama: {}", e.getMessage());
        }

        return analytics;
    }

    private String generate(String text, String instructionPrefix) {
        String prompt = instructionPrefix + text;
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("model", modelName);
        requestBody.put("prompt", prompt);
        requestBody.put("stream", false);

        try {
            Map<String, Object> response = this.webClient.post()
                    .uri("/api/generate")
                    .contentType(MediaType.APPLICATION_JSON)
                    .accept(MediaType.APPLICATION_JSON)
                    .bodyValue(requestBody)
                    .retrieve()
                    .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
                    })
                    .onErrorResume(err -> {
                        logger.warn("Ollama request failed: {}", err.getMessage());
                        return Mono.empty();
                    })
                    .block(Duration.ofMillis(timeoutMs));

            if (response == null) {
                return null;
            }

            Object res = response.get("response");
            return res == null ? null : String.valueOf(res);
        } catch (Exception e) {
            logger.warn("Error calling Ollama generate: {}", e.getMessage());
            return null;
        }
    }

    public String generateWithInstruction(String text, String instruction) {
        return generateWithInstruction(text, instruction, "ru");
    }

    public String generateWithInstruction(String text, String instruction, String language) {
        String prompt = instruction + "\n\n" + text;
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("model", modelName);
        requestBody.put("prompt", prompt);
        requestBody.put("stream", false);

        try {
            Map<String, Object> response = this.webClient.post()
                    .uri("/api/generate")
                    .contentType(MediaType.APPLICATION_JSON)
                    .accept(MediaType.APPLICATION_JSON)
                    .bodyValue(requestBody)
                    .retrieve()
                    .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
                    })
                    .onErrorResume(err -> {
                        logger.warn("Ollama request failed: {}", err.getMessage());
                        return Mono.empty();
                    })
                    .block(Duration.ofMillis(timeoutMs));

            if (response == null) {
                return null;
            }

            Object res = response.get("response");
            System.out.println("Ollama response: " + res);
            return res == null ? null : String.valueOf(res);
        } catch (Exception e) {
            logger.warn("Error calling Ollama generate (generic): {}", e.getMessage());
            return null;
        }
    }
}
