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;

/**
 * Anthropic Claude LLM 클라이언트.
 * /v1/messages 엔드포인트.
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class AnthropicLlmClient implements LlmClient {

    private static final String DEFAULT_BASE_URL = "https://api.anthropic.com";
    private static final String ANTHROPIC_VERSION = "2023-06-01";

    @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("claude-");
    }

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

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

        // OpenAI -> Anthropic 메시지 매핑
        List<Map<String, Object>> openaiMsgs = (List<Map<String, Object>>) request.getOrDefault("messages", List.of());
        String systemPrompt = openaiMsgs.stream()
                .filter(m -> "system".equals(m.get("role")))
                .map(m -> String.valueOf(m.get("content")))
                .findFirst().orElse(null);
        List<Map<String, Object>> anthropicMsgs = openaiMsgs.stream()
                .filter(m -> !"system".equals(m.get("role")))
                .map(m -> Map.of("role", String.valueOf(m.get("role")), "content", m.get("content")))
                .toList();

        Map<String, Object> body = new HashMap<>();
        body.put("model", request.get("model"));
        body.put("messages", anthropicMsgs);
        if (systemPrompt != null) body.put("system", systemPrompt);
        body.put("max_tokens", request.getOrDefault("max_tokens", 2000));
        if (request.get("temperature") != null) body.put("temperature", request.get("temperature"));

        try {
            Map<String, Object> resp = httpClient.post()
                    .uri(baseUrl + "/v1/messages")
                    .contentType(MediaType.APPLICATION_JSON)
                    .header("x-api-key", apiKey)
                    .header("anthropic-version", ANTHROPIC_VERSION)
                    .body(body)
                    .retrieve()
                    .body(Map.class);
            return convertToOpenAiFormat(resp, String.valueOf(request.get("model")));
        } catch (RestClientResponseException e) {
            log.error("Anthropic API 오류 {}: {}", e.getStatusCode().value(), e.getResponseBodyAsString());
            throw new LlmClientException("Anthropic API 오류: " + e.getMessage(), e.getStatusCode().value());
        } catch (Exception e) {
            throw new LlmClientException("Anthropic 호출 실패: " + e.getMessage(), e);
        }
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> convertToOpenAiFormat(Map<String, Object> anthropic, String model) {
        if (anthropic == null) return Map.of();

        // Anthropic content: [{type:"text", text:"..."}]
        String text = "";
        Object content = anthropic.get("content");
        if (content instanceof List<?> list && !list.isEmpty()) {
            Object first = list.get(0);
            if (first instanceof Map<?, ?> mapItem) {
                Object t = mapItem.get("text");
                if (t != null) text = String.valueOf(t);
            }
        }

        Map<String, Object> usageOut = new HashMap<>();
        Map<String, Object> usage = (Map<String, Object>) anthropic.getOrDefault("usage", Map.of());
        Number prompt = (Number) usage.getOrDefault("input_tokens", 0);
        Number completion = (Number) usage.getOrDefault("output_tokens", 0);
        usageOut.put("prompt_tokens", prompt.intValue());
        usageOut.put("completion_tokens", completion.intValue());
        usageOut.put("total_tokens", prompt.intValue() + completion.intValue());

        List<Map<String, Object>> choices = new ArrayList<>();
        choices.add(Map.of(
                "index", 0,
                "message", Map.of("role", "assistant", "content", text),
                "finish_reason", anthropic.getOrDefault("stop_reason", "stop")
        ));

        Map<String, Object> out = new HashMap<>();
        out.put("id", anthropic.getOrDefault("id", "chatcmpl-" + UUID.randomUUID()));
        out.put("object", "chat.completion");
        out.put("created", System.currentTimeMillis() / 1000);
        out.put("model", model);
        out.put("choices", choices);
        out.put("usage", usageOut);
        return out;
    }
}
