package com.erp.ai.service;

import com.erp.ai.dto.AgentRequest;
import com.erp.ai.exception.AiAgentException;
import com.erp.ai.mapper.AiAgentMapper;
import com.erp.ai.model.AiAgent;
import com.fasterxml.jackson.core.JsonProcessingException;
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;

/**
 * AI 에이전트 CRUD 서비스.
 * vexplor aiAgentService.ts 1:1 포팅.
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AiAgentService {

    private final AiAgentMapper agentMapper;

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

    public List<Map<String, Object>> list(String status, String companyCode, String search) {
        Map<String, Object> filters = new HashMap<>();
        if (status != null) filters.put("status", status);
        if (companyCode != null) filters.put("company_code", companyCode);
        if (search != null && !search.isBlank()) filters.put("search", "%" + search + "%");
        return agentMapper.list(filters).stream().map(this::toResponseMap).toList();
    }

    public Map<String, Object> getById(long id) {
        AiAgent agent = agentMapper.getById(id);
        if (agent == null) return null;
        return toResponseMap(agent);
    }

    /** 내부용 — model 원본 반환 (MultiAgentExecutionEngine 등 LLM 호출 경로는 agentMapper 직접 사용) */
    public AiAgent getEntityById(long id) {
        return agentMapper.getById(id);
    }

    public AiAgent getByAgentId(String agentId) {
        return agentMapper.getByAgentId(agentId);
    }

    private Map<String, Object> toResponseMap(AiAgent a) {
        Map<String, Object> row = new HashMap<>();
        row.put("id", a.getId());
        row.put("agent_id", a.getAgent_id());
        row.put("name", a.getName());
        row.put("description", a.getDescription());
        row.put("model", a.getModel());
        row.put("system_prompt", a.getSystem_prompt());
        row.put("tools", a.getTools());
        row.put("config", a.getConfig());
        row.put("status", a.getStatus());
        row.put("company_code", a.getCompany_code());
        row.put("created_by", a.getCreated_by());
        row.put("created_at", a.getCreated_at());
        row.put("updated_at", a.getUpdated_at());
        parseJsonField(row, "tools");
        parseJsonField(row, "config");
        return row;
    }

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

    @Transactional
    public AiAgent create(AgentRequest req, String userId) {
        if (req.getAgent_id() == null || req.getAgent_id().isBlank()) {
            throw new AiAgentException("agent_id 가 필요합니다.");
        }
        if (agentMapper.getByAgentId(req.getAgent_id()) != null) {
            throw new AiAgentException("이미 존재하는 에이전트 ID입니다.");
        }

        AiAgent agent = new AiAgent();
        agent.setAgent_id(req.getAgent_id());
        agent.setName(req.getName());
        agent.setDescription(req.getDescription());
        agent.setModel(req.getModel());
        agent.setSystem_prompt(req.getSystem_prompt());
        agent.setTools(toJsonString(req.getTools()));
        agent.setConfig(toJsonString(req.getConfig()));
        agent.setStatus(req.getStatus() != null ? req.getStatus() : "active");
        agent.setCompany_code(req.getCompany_code());
        agent.setCreated_by(userId);

        agentMapper.insert(agent);
        log.info("에이전트 생성: {} (by {})", req.getAgent_id(), userId);
        return agentMapper.getById(agent.getId());
    }

    @Transactional
    public AiAgent update(long id, AgentRequest req) {
        AiAgent existing = agentMapper.getById(id);
        if (existing == null) return null;

        Map<String, Object> fields = new HashMap<>();
        if (req.getName() != null) fields.put("name", req.getName());
        if (req.getDescription() != null) fields.put("description", req.getDescription());
        if (req.getModel() != null) fields.put("model", req.getModel());
        if (req.getSystem_prompt() != null) fields.put("system_prompt", req.getSystem_prompt());
        if (req.getTools() != null) fields.put("tools", toJsonString(req.getTools()));
        if (req.getConfig() != null) fields.put("config", toJsonString(req.getConfig()));
        if (req.getStatus() != null) fields.put("status", req.getStatus());

        if (!fields.isEmpty()) {
            agentMapper.update(id, fields);
        }
        return agentMapper.getById(id);
    }

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

    public List<AiAgent> getActiveAgents() {
        return agentMapper.getActiveAgents();
    }

    private String toJsonString(Object value) {
        if (value == null) return null;
        try {
            return objectMapper.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new AiAgentException("JSON 직렬화 실패", e);
        }
    }
}
