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

import com.infoepoch.pms.agent.common.utils.LogHelper;
import com.infoepoch.pms.agent.common.utils.OracleUtils;
import com.infoepoch.pms.agent.platform.model.domain.AiModelProvider;
import com.infoepoch.pms.agent.platform.model.domain.irepository.AiModelProviderCriteria;
import com.infoepoch.pms.agent.platform.model.domain.irepository.IAiModelProviderRepository;
import com.infoepoch.pms.agent.platform.shared.adapter.out.crypto.AesEncryptConverter;
import com.infoepoch.pms.agent.platform.shared.exception.ValidationException;
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.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

@Repository
public class AiModelProviderRepository implements IAiModelProviderRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private AesEncryptConverter aesEncryptConverter;

    /**
     * 新增
     */
    @Override
    public boolean insert(AiModelProvider entity) {
        String sql = "INSERT INTO AI_MODEL_PROVIDER(ID, NAME, TYPE, BASE_URL, API_KEY, DESCRIPTION, IS_ACTIVE, CREATED_USER_ID, UPDATED_USER_ID, CREATED_AT, UPDATED_AT, CUSTOM_HEADERS) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        int result;
        try {
            result = jdbcTemplate.update(sql, entity.getId(), entity.getName(), entity.getType(), entity.getBaseUrl(),
                    encryptApiKey(entity.getApiKey()), entity.getDescription(), entity.isActive(),
                    entity.getCreatedUserId(), entity.getUpdatedUserId(), Timestamp.valueOf(entity.getCreatedAt()),
                    Timestamp.valueOf(entity.getUpdatedAt()), entity.getCustomHeadersJson());
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            throw new ValidationException("新增 AI 模型供应商配置表 数据 失败。");
        }
        return result > 0;
    }

    /**
     * 更新
     */
    @Override
    public boolean update(AiModelProvider entity) {
        String sql = "UPDATE AI_MODEL_PROVIDER SET NAME = ?, TYPE = ?, BASE_URL = ?, API_KEY = ?, DESCRIPTION = ?, IS_ACTIVE = ?, CREATED_USER_ID = ?, UPDATED_USER_ID = ?, CREATED_AT = ?, UPDATED_AT = ?, CUSTOM_HEADERS = ? WHERE ID = ?";
        int result;
        try {
            result = jdbcTemplate.update(sql, entity.getName(), entity.getType(), entity.getBaseUrl(),
                    encryptApiKey(entity.getApiKey()), entity.getDescription(), entity.isActive(),
                    entity.getCreatedUserId(), entity.getUpdatedUserId(),
                    entity.getCreatedAt() != null ? Timestamp.valueOf(entity.getCreatedAt()) : null,
                    entity.getUpdatedAt() != null ? Timestamp.valueOf(entity.getUpdatedAt()) : null,
                    entity.getCustomHeadersJson(), entity.getId());
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            throw new ValidationException("更新 AI 模型供应商配置表 数据 失败。");
        }
        return result >= 0;
    }

    /**
     * 批量新增
     */
    public int[] batchInsert(List<AiModelProvider> list) {
        String sql = "INSERT INTO AI_MODEL_PROVIDER(ID, NAME, TYPE, BASE_URL, API_KEY, DESCRIPTION, IS_ACTIVE, CREATED_USER_ID, UPDATED_USER_ID, CREATED_AT, UPDATED_AT, CUSTOM_HEADERS) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        int[] result = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                int j = 0;
                AiModelProvider item = list.get(i);
                ps.setString(++j, item.getId());
                ps.setString(++j, item.getName());
                ps.setString(++j, item.getType());
                ps.setString(++j, item.getBaseUrl());
                ps.setString(++j, encryptApiKey(item.getApiKey()));
                ps.setString(++j, item.getDescription());
                ps.setBoolean(++j, item.isActive());
                ps.setString(++j, item.getCreatedUserId());
                ps.setString(++j, item.getUpdatedUserId());
                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.getCustomHeadersJson());
            }

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

    /**
     * 批量更新
     */
    public int[] batchUpdate(List<AiModelProvider> list) {
        String sql = "UPDATE AI_MODEL_PROVIDER SET NAME = ?, TYPE = ?, BASE_URL = ?, API_KEY = ?, DESCRIPTION = ?, IS_ACTIVE = ?, CREATED_USER_ID = ?, UPDATED_USER_ID = ?, CREATED_AT = ?, UPDATED_AT = ?, CUSTOM_HEADERS = ? WHERE ID = ? ";
        int[] result = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                int j = 0;
                AiModelProvider item = list.get(i);
                ps.setString(++j, item.getName());
                ps.setString(++j, item.getType());
                ps.setString(++j, item.getBaseUrl());
                ps.setString(++j, encryptApiKey(item.getApiKey()));
                ps.setString(++j, item.getDescription());
                ps.setBoolean(++j, item.isActive());
                ps.setString(++j, item.getCreatedUserId());
                ps.setString(++j, item.getUpdatedUserId());
                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.getCustomHeadersJson());
                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_MODEL_PROVIDER WHERE ID = ?";
        int result;
        try {
            result = jdbcTemplate.update(sql, id);
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            throw new ValidationException("删除 AI 模型供应商配置表 数据 失败。");
        }
        return result > 0;
    }

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

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

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

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

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

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

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

    @Override
    public boolean existsById(String id) {
        return findById(id).isPresent();
    }

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

    @Override
    public boolean existsByNameAndIdNot(String name, String id) {
        AiModelProviderCriteria criteria = new AiModelProviderCriteria();
        criteria.setName(name == null ? null : name.trim());
        List<AiModelProvider> providers = selectByCriteria(criteria);
        if (providers == null) {
            return false;
        }
        return providers.stream().anyMatch(provider -> !Objects.equals(provider.getId(), id));
    }

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

    /**
     * RowMapper
     */
    private class AiModelProviderRowMapper implements RowMapper<AiModelProvider> {
        @Override
        public AiModelProvider mapRow(ResultSet rs, int i) throws SQLException {
            return new AiModelProvider(
                    rs.getString("ID"),
                    rs.getString("NAME"),
                    rs.getString("TYPE"),
                    rs.getString("BASE_URL"),
                    decryptApiKey(rs.getString("API_KEY")),
                    rs.getString("CUSTOM_HEADERS"),
                    rs.getString("DESCRIPTION"),
                    rs.getObject("IS_ACTIVE") == null || rs.getBoolean("IS_ACTIVE"),
                    rs.getString("CREATED_USER_ID"),
                    rs.getString("UPDATED_USER_ID"),
                    rs.getTimestamp("CREATED_AT").toLocalDateTime(),
                    rs.getTimestamp("UPDATED_AT").toLocalDateTime()
            );
        }
    }

    /**
     * 创建查询条件
     */
    private Map<String, Object> createCriteriaSql(AiModelProviderCriteria 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());
        //供应商显示名称（LIKE）
        if (criteria.byNameContain())
            andMap.put(" NAME LIKE ? ", "%" + criteria.getNameContain() + "%");
        //供应商类型，如 OPENAI 或 DASHSCOPE
        if (criteria.byType())
            andMap.put(criteria.getType() == null ? " TYPE IS NULL " : " TYPE = ? ", criteria.getType());
        //供应商类型，如 OPENAI 或 DASHSCOPE（LIKE）
        if (criteria.byTypeContain())
            andMap.put(" TYPE LIKE ? ", "%" + criteria.getTypeContain() + "%");
        //供应商 API 基础 URL
        if (criteria.byBaseUrl())
            andMap.put(criteria.getBaseUrl() == null ? " BASE_URL IS NULL " : " BASE_URL = ? ", criteria.getBaseUrl());
        //供应商 API 基础 URL（LIKE）
        if (criteria.byBaseUrlContain())
            andMap.put(" BASE_URL LIKE ? ", "%" + criteria.getBaseUrlContain() + "%");
        //供应商是否启用
        if (criteria.byActive())
            andMap.put(criteria.getActive() == null ? " IS_ACTIVE IS NULL " : " IS_ACTIVE = ? ", criteria.getActive());
        return andMap;
    }

    private String encryptApiKey(String apiKey) {
        return aesEncryptConverter == null ? apiKey : aesEncryptConverter.encrypt(apiKey);
    }

    private String decryptApiKey(String cipherText) {
        return aesEncryptConverter == null ? cipherText : aesEncryptConverter.decrypt(cipherText);
    }

}
