package com.infoepoch.pms.agent.platform.chatbot.adapter.out.persistence;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.infoepoch.pms.agent.common.utils.LogHelper;
import com.infoepoch.pms.agent.common.utils.OracleUtils;
import com.infoepoch.pms.agent.platform.agent.adapter.out.persistence.AgentRepository;
import com.infoepoch.pms.agent.platform.agent.domain.Agent;
import com.infoepoch.pms.agent.platform.chatbot.domain.Chatbot;
import com.infoepoch.pms.agent.platform.chatbot.domain.irepository.ChatbotCriteria;
import com.infoepoch.pms.agent.platform.chatbot.domain.irepository.IChatbotRepository;
import com.infoepoch.pms.agent.platform.model.adapter.out.persistence.AiModelConfigRepository;
import com.infoepoch.pms.agent.platform.shared.exception.ValidationException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 聊天机器人定义仓储实现
 */
@Repository
public class ChatbotRepository implements IChatbotRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 新增
     */
    @Override
    public boolean insert(Chatbot entity) {
        String sql = "INSERT INTO AI_CHATBOTS(ID, NAME, DESCRIPTION, SYSTEM_PROMPT, MODEL_CONFIG_ID, ENABLED_TOOLS, CONTEXT_WINDOW_SIZE, ENABLED, CREATED_AT, UPDATED_AT) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        int result;
        try {
            result = jdbcTemplate.update(sql, entity.getId(), entity.getName(), entity.getDescription(), entity.getSystemPrompt(), entity.getModelConfigId(), entity.getEnabledToolsJson(), entity.getContextWindowSize(), entity.isEnabled(), entity.getCreatedAt() != null ? Timestamp.valueOf(entity.getCreatedAt()) : null, entity.getUpdatedAt() != null ? Timestamp.valueOf(entity.getUpdatedAt()) : null);
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            throw new ValidationException("新增 聊天机器人定义 数据 失败。");
        }
        return result > 0;
    }

    /**
     * 更新
     */
    @Override
    public boolean update(Chatbot entity) {
        String sql = "UPDATE AI_CHATBOTS SET NAME = ?, DESCRIPTION = ?, SYSTEM_PROMPT = ?, MODEL_CONFIG_ID = ?, ENABLED_TOOLS = ?, CONTEXT_WINDOW_SIZE = ?, ENABLED = ?, CREATED_AT = ?, UPDATED_AT = ? WHERE ID = ?";
        int result;
        try {
            result = jdbcTemplate.update(sql, entity.getName(), entity.getDescription(), entity.getSystemPrompt(), entity.getModelConfigId(), entity.getEnabledToolsJson(), entity.getContextWindowSize(), entity.isEnabled(), entity.getCreatedAt() != null ? Timestamp.valueOf(entity.getCreatedAt()) : null, entity.getUpdatedAt() != null ? Timestamp.valueOf(entity.getUpdatedAt()) : null, entity.getId());
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            throw new ValidationException("更新 聊天机器人定义 数据 失败。");
        }
        return result >= 0;
    }

    /**
     * 批量新增
     */
    public int[] batchInsert(List<Chatbot> list) {
        String sql = "INSERT INTO AI_CHATBOTS(ID, NAME, DESCRIPTION, SYSTEM_PROMPT, MODEL_CONFIG_ID, ENABLED_TOOLS, CONTEXT_WINDOW_SIZE, ENABLED, CREATED_AT, UPDATED_AT) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        int[] result = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                int j = 0;
                Chatbot item = list.get(i);
                ps.setString(++j, item.getId());
                ps.setString(++j, item.getName());
                ps.setString(++j, item.getDescription());
                ps.setString(++j, item.getSystemPrompt());
                ps.setString(++j, item.getModelConfigId());
                ps.setString(++j, item.getEnabledToolsJson());
                ps.setObject(++j, item.getContextWindowSize());
                ps.setBoolean(++j, item.isEnabled());
                ps.setTimestamp(++j, item.getCreatedAt() != null ? Timestamp.valueOf(item.getCreatedAt()) : null);
                ps.setTimestamp(++j, item.getUpdatedAt() != null ? Timestamp.valueOf(item.getUpdatedAt()) : null);
            }

            @Override
            public int getBatchSize() {
                return list.size();
            }
        });
        return result;
    }

    /**
     * 批量更新
     */
    public int[] batchUpdate(List<Chatbot> list) {
        String sql = "UPDATE AI_CHATBOTS SET NAME = ?, DESCRIPTION = ?, SYSTEM_PROMPT = ?, MODEL_CONFIG_ID = ?, ENABLED_TOOLS = ?, CONTEXT_WINDOW_SIZE = ?, ENABLED = ?, CREATED_AT = ?, UPDATED_AT = ? WHERE ID = ? ";
        int[] result = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                int j = 0;
                Chatbot item = list.get(i);
                ps.setString(++j, item.getName());
                ps.setString(++j, item.getDescription());
                ps.setString(++j, item.getSystemPrompt());
                ps.setString(++j, item.getModelConfigId());
                ps.setString(++j, item.getEnabledToolsJson());
                ps.setObject(++j, item.getContextWindowSize());
                ps.setBoolean(++j, item.isEnabled());
                ps.setTimestamp(++j, item.getCreatedAt() != null ? Timestamp.valueOf(item.getCreatedAt()) : null);
                ps.setTimestamp(++j, item.getUpdatedAt() != null ? Timestamp.valueOf(item.getUpdatedAt()) : null);
                ps.setString(++j, item.getId());
            }

            @Override
            public int getBatchSize() {
                return list.size();
            }
        });
        return result;
    }

    /**
     * 删除
     */
    @Override
    public boolean delete(String id) {
        String sql = "DELETE FROM AI_CHATBOTS WHERE ID = ?";
        int result;
        try {
            result = jdbcTemplate.update(sql, id);
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            throw new ValidationException("删除 聊天机器人定义 数据 失败。");
        }
        return result > 0;
    }

    /**
     * 根据Id查询
     */
    @Override
    public Chatbot selectById(String id) {
        String sql = "SELECT * FROM AI_CHATBOTS WHERE ID = ? ";
        try {
            return jdbcTemplate.queryForObject(sql, new ChatbotRowMapper(), id);
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            return null;
        }
    }

    /**
     * 根据查询条件查询单个对象
     */
    @Override
    public Chatbot selectOneByCriteria(ChatbotCriteria criteria) {
        StringBuffer buffer = new StringBuffer("SELECT * FROM AI_CHATBOTS ");
        List<Object> list = OracleUtils.combinationSql(buffer, createCriteriaSql(criteria), 1, 1);
        try {
            return jdbcTemplate.queryForObject(buffer.toString(), list.toArray(), new ChatbotRowMapper());
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            return null;
        }
    }

    /**
     * 根据查询条件查询对象集合
     */
    @Override
    public List<Chatbot> selectByCriteria(ChatbotCriteria criteria) {
        StringBuffer buffer = new StringBuffer("SELECT * FROM AI_CHATBOTS ");
        List<Object> list = OracleUtils.combinationSql(buffer, createCriteriaSql(criteria));
        try {
            return jdbcTemplate.query(buffer.toString(), list.toArray(), new ChatbotRowMapper());
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            return null;
        }
    }

    /**
     * 根据查询条件分页查询对象结合
     */
    @Override
    public List<Chatbot> selectCriteriaByPage(ChatbotCriteria criteria, int pageNum, int pageSize) {
        StringBuffer buffer = new StringBuffer("SELECT * FROM AI_CHATBOTS ");
        List<Object> list = OracleUtils.combinationSql(buffer, createCriteriaSql(criteria), pageNum, pageSize);
        try {
            return jdbcTemplate.query(buffer.toString(), list.toArray(), new ChatbotRowMapper());
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            return null;
        }
    }

    /**
     * 根据条件查询对象总记录数
     */
    @Override
    public Integer selectCountByCriteria(ChatbotCriteria criteria) {
        StringBuffer buffer = new StringBuffer("SELECT COUNT(*) FROM AI_CHATBOTS ");
        List<Object> list = OracleUtils.combinationSql(buffer, createCriteriaSql(criteria));
        int count = jdbcTemplate.queryForObject(buffer.toString(), list.toArray(), int.class);
        return count;
    }

    @Override
    public Optional<Chatbot> findById(String id) {
        return Optional.ofNullable(id).map(this::selectById);
    }

    @Override
    public Chatbot save(Chatbot entity) {
        if (entity == null) {
            return null;
        }
        if (findById(entity.getId()).isPresent()) {
            update(entity);
        } else {
            insert(entity);
        }
        return entity;
    }

    @Override
    public boolean existsByTrimmedName(String name) {
        ChatbotCriteria criteria = new ChatbotCriteria();
        criteria.setName(name == null ? null : name.trim());
        return selectCountByCriteria(criteria) > 0;
    }

    @Override
    public boolean existsByTrimmedNameAndIdNot(String name, String id) {
        ChatbotCriteria criteria = new ChatbotCriteria();
        criteria.setName(name == null ? null : name.trim());
        List<Chatbot> chatbots = selectByCriteria(criteria);
        if (chatbots == null) {
            return false;
        }
        return chatbots.stream().anyMatch(chatbot -> !Objects.equals(chatbot.getId(), id));
    }

    @Override
    public boolean existsByModelConfigId(String modelConfigId) {
        ChatbotCriteria criteria = new ChatbotCriteria();
        criteria.setModelConfigId(modelConfigId);
        return selectCountByCriteria(criteria) > 0;
    }

    @Override
    public List<Chatbot> findAllByOrderByCreatedAtDesc() {
        List<Chatbot> chatbots = selectByCriteria(null);
        if (chatbots == null) {
            return List.of();
        }
        return chatbots.stream()
                .sorted((left, right) -> right.getCreatedAt().compareTo(left.getCreatedAt()))
                .toList();
    }

    /**
     * RowMapper
     */
    private class ChatbotRowMapper implements RowMapper<Chatbot> {
        @Override
        public Chatbot mapRow(ResultSet rs, int i) throws SQLException {
            return new Chatbot(
                    rs.getString("ID"),
                    rs.getString("NAME"),
                    rs.getString("DESCRIPTION"),
                    rs.getString("SYSTEM_PROMPT"),
                    rs.getString("MODEL_CONFIG_ID"),
                    rs.getString("ENABLED_TOOLS"),
                    rs.getObject("CONTEXT_WINDOW_SIZE") != null ? rs.getInt("CONTEXT_WINDOW_SIZE") : 20,
                    rs.getObject("ENABLED") != null ? rs.getBoolean("ENABLED") : true,
                    rs.getTimestamp("CREATED_AT").toLocalDateTime(),
                    rs.getTimestamp("UPDATED_AT").toLocalDateTime()
            );
        }
    }

    /**
     * 创建查询条件
     */
    private Map<String, Object> createCriteriaSql(ChatbotCriteria criteria) {
        Map<String, Object> andMap = new LinkedHashMap<>();
        if (criteria == null)
            return andMap;

        //聊天机器人名称，系统内唯一
        if (criteria.byName())
            andMap.put(criteria.getName() == null ? " NAME IS NULL " : " NAME = ? ", criteria.getName());
        //绑定的模型配置主键，为空则使用系统默认模型
        if (criteria.byModelConfigId())
            andMap.put(criteria.getModelConfigId() == null ? " MODEL_CONFIG_ID IS NULL " : " MODEL_CONFIG_ID = ? ", criteria.getModelConfigId());
        //聊天机器人是否启用
        if (criteria.byEnabled())
            andMap.put(criteria.getEnabled() == null ? " ENABLED IS NULL " : " ENABLED = ? ", criteria.getEnabled());
        return andMap;
    }

}
