package com.erp.ai.client;

import com.erp.ai.exception.LlmClientException;
import com.erp.ai.mapper.AiLlmProviderMapper;
import com.erp.ai.model.AiLlmProvider;
import com.erp.ai.util.AesGcmCipher;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientResponseException;

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

/**
 * Google Gemini LLM 클라이언트.
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class GeminiLlmClient implements LlmClient {

    private static final String DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com";

    @Qualifier("llmRestClient")
    private final RestClient httpClient;
    private final AiLlmProviderMapper providerMapper;
    private final AesGcmCipher cipher;

    @Override
    public boolean supports(String model) {
        return model != null && model.startsWith("gemini-");
    }

    @Override
    public String providerName() {
        return "google";
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<String, Object> chat(Map<String, Object> request) {
        AiLlmProvider provider = providerMapper.getByName("google");
        if (provider == null || !Boolean.TRUE.equals(provider.getIs_active())) {
            throw new LlmClientException("Google 프로바이더가 활성화되지 않았습니다.");
        }
        String apiKey = cipher.decrypt(provider.getApi_key_encrypted());
        String baseUrl = provider.getEndpoint() != null ? provider.getEndpoint() : DEFAULT_BASE_URL;
        String model = String.valueOf(request.get("model"));

        // OpenAI messages -> Gemini contents
        List<Map<String, Object>> openaiMsgs = (List<Map<String, Object>>) request.getOrDefault("messages", List.of());
        List<Map<String, Object>> geminiContents = new ArrayList<>();
        StringBuilder systemBuf = new StringBuilder();
        for (Map<String, Object> m : openaiMsgs) {
            String role = String.valueOf(m.get("role"));
            String content = String.valueOf(m.get("content"));
            if ("system".equals(role)) {
                systemBuf.append(content).append("\n");
            } else {
                String mapped = "assistant".equals(role) ? "model" : "user";
                geminiContents.add(Map.of(
                        "role", mapped,
                        "parts", List.of(Map.of("text", content))
                ));
            }
        }

        Map<String, Object> body = new HashMap<>();
        body.put("contents", geminiContents);
        if (systemBuf.length() > 0) {
            body.put("systemInstruction", Map.of("parts", List.of(Map.of("text", systemBuf.toString()))));
        }
        Map<String, Object> genConfig = new HashMap<>();
        if (request.get("max_tokens") != null) genConfig.put("maxOutputTokens", request.get("max_tokens"));
        if (request.get("temperature") != null) genConfig.put("temperature", request.get("temperature"));
        if (!genConfig.isEmpty()) body.put("generationConfig", genConfig);

        try {
            Map<String, Object> resp = httpClient.post()
                    .uri(baseUrl + "/v1beta/models/" + model + ":generateContent?key=" + apiKey)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(body)
                    .retrieve()
                    .body(Map.class);
            return convertToOpenAiFormat(resp, model);
        } catch (RestClientResponseException e) {
            log.error("Gemini API 오류 {}: {}", e.getStatusCode().value(), e.getResponseBodyAsString());
            throw new LlmClientException("Gemini API 오류: " + e.getMessage(), e.getStatusCode().value());
        } catch (Exception e) {
            throw new LlmClientException("Gemini 호출 실패: " + e.getMessage(), e);
        }
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> convertToOpenAiFormat(Map<String, Object> gemini, String model) {
        if (gemini == null) return Map.of();
        String text = "";
        List<Map<String, Object>> candidates = (List<Map<String, Object>>) gemini.getOrDefault("candidates", List.of());
        if (!candidates.isEmpty()) {
            Map<String, Object> first = candidates.get(0);
            Map<String, Object> content = (Map<String, Object>) first.get("content");
            if (content != null) {
                List<Map<String, Object>> parts = (List<Map<String, Object>>) content.getOrDefault("parts", List.of());
                if (!parts.isEmpty()) {
                    Object t = parts.get(0).get("text");
                    if (t != null) text = String.valueOf(t);
                }
            }
        }

        Map<String, Object> usageMeta = (Map<String, Object>) gemini.getOrDefault("usageMetadata", Map.of());
        Number prompt = (Number) usageMeta.getOrDefault("promptTokenCount", 0);
        Number completion = (Number) usageMeta.getOrDefault("candidatesTokenCount", 0);
        Number total = (Number) usageMeta.getOrDefault("totalTokenCount", prompt.intValue() + completion.intValue());

        Map<String, Object> usageOut = new HashMap<>();
        usageOut.put("prompt_tokens", prompt.intValue());
        usageOut.put("completion_tokens", completion.intValue());
        usageOut.put("total_tokens", total.intValue());

        Map<String, Object> out = new HashMap<>();
        out.put("id", "chatcmpl-" + UUID.randomUUID());
        out.put("object", "chat.completion");
        out.put("created", System.currentTimeMillis() / 1000);
        out.put("model", model);
        out.put("choices", List.of(Map.of(
                "index", 0,
                "message", Map.of("role", "assistant", "content", text),
                "finish_reason", "stop")));
        out.put("usage", usageOut);
        return out;
    }
}
