package com.erp.ai.service;

import com.erp.ai.dto.ProviderRequest;
import com.erp.ai.exception.AiAgentException;
import com.erp.ai.mapper.AiLlmProviderMapper;
import com.erp.ai.model.AiLlmProvider;
import com.erp.ai.util.AesGcmCipher;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * LLM 프로바이더 관리 서비스.
 * vexplor aiAgentProviderService.ts 1:1 포팅.
 * - LLM API 키는 AES-GCM 암호화 저장
 * - 목록 조회 시 키 마스킹 (****+last4)
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AiAgentProviderService {

    private final AiLlmProviderMapper providerMapper;
    private final AesGcmCipher cipher;

    @Qualifier("aiObjectMapper")
    private final ObjectMapper objectMapper;

    /** 키 마스킹된 목록 */
    public List<Map<String, Object>> list() {
        return providerMapper.listAll().stream()
                .map(this::toMaskedMap)
                .toList();
    }

    public Map<String, Object> getById(long id) {
        AiLlmProvider p = providerMapper.getById(id);
        if (p == null) return null;
        return toMaskedMap(p);
    }

    /** 내부용 — model 원본 반환 (getActiveProviders, LLM 호출 경로) */
    public AiLlmProvider getEntityById(long id) {
        return providerMapper.getById(id);
    }

    public List<AiLlmProvider> getActiveProviders() {
        return providerMapper.listActive();
    }

    @Transactional
    public AiLlmProvider create(ProviderRequest req) {
        if (req.getApi_key() == null || req.getApi_key().isBlank()) {
            throw new AiAgentException("api_key 가 필요합니다.");
        }
        AiLlmProvider provider = new AiLlmProvider();
        provider.setName(req.getName());
        provider.setDisplay_name(req.getDisplay_name());
        provider.setApi_key_encrypted(cipher.encrypt(req.getApi_key()));
        provider.setModel_name(req.getModel_name());
        provider.setEndpoint(req.getEndpoint());
        provider.setPriority(req.getPriority());
        provider.setMax_tokens(req.getMax_tokens());
        provider.setTemperature(req.getTemperature());
        provider.setCost_per_1k_input(req.getCost_per_1k_input());
        provider.setCost_per_1k_output(req.getCost_per_1k_output());
        provider.setIs_active(req.getIs_active() != null ? req.getIs_active() : Boolean.TRUE);

        providerMapper.insert(provider);
        log.info("LLM 프로바이더 추가: {} ({})", req.getName(), req.getModel_name());
        return providerMapper.getById(provider.getId());
    }

    @Transactional
    public AiLlmProvider update(long id, ProviderRequest req) {
        AiLlmProvider existing = providerMapper.getById(id);
        if (existing == null) return null;

        AiLlmProvider provider = new AiLlmProvider();
        provider.setId(id);
        provider.setDisplay_name(req.getDisplay_name());
        if (req.getApi_key() != null && !req.getApi_key().isBlank()) {
            provider.setApi_key_encrypted(cipher.encrypt(req.getApi_key()));
        }
        provider.setModel_name(req.getModel_name());
        provider.setEndpoint(req.getEndpoint());
        provider.setPriority(req.getPriority());
        provider.setMax_tokens(req.getMax_tokens());
        provider.setTemperature(req.getTemperature());
        provider.setCost_per_1k_input(req.getCost_per_1k_input());
        provider.setCost_per_1k_output(req.getCost_per_1k_output());
        provider.setIs_active(req.getIs_active());

        providerMapper.update(provider);
        return providerMapper.getById(id);
    }

    @Transactional
    public void delete(long id) {
        providerMapper.delete(id);
    }

    /** 복호화된 키 반환 (서비스 내부에서만 사용) */
    public String getDecryptedKey(long id) {
        AiLlmProvider p = providerMapper.getById(id);
        if (p == null) return null;
        return cipher.decrypt(p.getApi_key_encrypted());
    }

    private Map<String, Object> toMaskedMap(AiLlmProvider p) {
        Map<String, Object> m = new HashMap<>();
        m.put("id", p.getId());
        m.put("name", p.getName());
        m.put("display_name", p.getDisplay_name());
        m.put("model_name", p.getModel_name());
        m.put("endpoint", p.getEndpoint());
        m.put("priority", p.getPriority());
        m.put("max_tokens", p.getMax_tokens());
        m.put("temperature", p.getTemperature());
        m.put("cost_per_1k_input", p.getCost_per_1k_input());
        m.put("cost_per_1k_output", p.getCost_per_1k_output());
        m.put("is_active", p.getIs_active());
        m.put("config", p.getConfig());
        m.put("created_at", p.getCreated_at());
        m.put("updated_at", p.getUpdated_at());
        // 마스킹: 마지막 4글자만 노출
        String enc = p.getApi_key_encrypted();
        m.put("api_key_masked", enc != null && enc.length() >= 4 ? "****" + enc.substring(enc.length() - 4) : "");
        parseJsonField(m, "config");
        return m;
    }

    private void parseJsonField(Map<String, Object> row, String key) {
        Object val = row.get(key);
        if (val instanceof String s && !s.isBlank()) {
            try {
                row.put(key, objectMapper.readValue(s, Object.class));
            } catch (Exception e) {
                log.warn("Failed to parse JSONB field '{}': {}", key, e.getMessage());
            }
        }
    }
}
