package com.infoepoch.pms.agent.platform.agent.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.domain.AgentField;
import com.infoepoch.pms.agent.platform.agent.domain.irepository.AgentFieldCriteria;
import com.infoepoch.pms.agent.platform.agent.domain.irepository.IAgentFieldRepository;
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.Optional;

/**
 * 智能体字段定义仓储实现
 */
@Repository
public class AgentFieldRepository implements IAgentFieldRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 新增
     */
    @Override
    public boolean insert(AgentField entity) {
        String sql = "INSERT INTO AI_AGENT_FIELDS(ID, AGENT_ID, FIELD_NAME, FIELD_LABEL, FIELD_TYPE, DATE_FORMAT, ENUM_OPTIONS, REQUIRED, DESCRIPTION, SORT_ORDER, CREATED_AT) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        int result;
        try {
            result = jdbcTemplate.update(sql, entity.getId(), entity.getAgentId(), entity.getFieldName(), entity.getFieldLabel(), entity.getFieldType(), entity.getDateFormat(), entity.getEnumOptionsJson(), entity.isRequired(), entity.getDescription(), entity.getSortOrder(), entity.getCreatedAt() != null ? Timestamp.valueOf(entity.getCreatedAt()) : null);
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            throw new ValidationException("新增 智能体字段定义 数据 失败。");
        }
        return result > 0;
    }

    /**
     * 更新
     */
    @Override
    public boolean update(AgentField entity) {
        String sql = "UPDATE AI_AGENT_FIELDS SET AGENT_ID = ?, FIELD_NAME = ?, FIELD_LABEL = ?, FIELD_TYPE = ?, DATE_FORMAT = ?, ENUM_OPTIONS = ?, REQUIRED = ?, DESCRIPTION = ?, SORT_ORDER = ?, CREATED_AT = ? WHERE ID = ?";
        int result;
        try {
            result = jdbcTemplate.update(sql, entity.getAgentId(), entity.getFieldName(), entity.getFieldLabel(), entity.getFieldType(), entity.getDateFormat(), entity.getEnumOptionsJson(), entity.isRequired(), entity.getDescription(), entity.getSortOrder(), entity.getCreatedAt() != null ? Timestamp.valueOf(entity.getCreatedAt()) : null, entity.getId());
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            throw new ValidationException("更新 智能体字段定义 数据 失败。");
        }
        return result >= 0;
    }

    /**
     * 批量新增
     */
    public int[] batchInsert(List<AgentField> list) {
        String sql = "INSERT INTO AI_AGENT_FIELDS(ID, AGENT_ID, FIELD_NAME, FIELD_LABEL, FIELD_TYPE, DATE_FORMAT, ENUM_OPTIONS, REQUIRED, DESCRIPTION, SORT_ORDER, CREATED_AT) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        int[] result = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                int j = 0;
                AgentField item = list.get(i);
                ps.setString(++j, item.getId());
                ps.setString(++j, item.getAgentId());
                ps.setString(++j, item.getFieldName());
                ps.setString(++j, item.getFieldLabel());
                ps.setString(++j, item.getFieldType());
                ps.setString(++j, item.getDateFormat());
                ps.setString(++j, item.getEnumOptionsJson());
                ps.setBoolean(++j, item.isRequired());
                ps.setString(++j, item.getDescription());
                ps.setObject(++j, item.getSortOrder());
                ps.setTimestamp(++j, item.getCreatedAt() != null ? Timestamp.valueOf(item.getCreatedAt()) : null);
            }

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

    /**
     * 批量更新
     */
    public int[] batchUpdate(List<AgentField> list) {
        String sql = "UPDATE AI_AGENT_FIELDS SET AGENT_ID = ?, FIELD_NAME = ?, FIELD_LABEL = ?, FIELD_TYPE = ?, DATE_FORMAT = ?, ENUM_OPTIONS = ?, REQUIRED = ?, DESCRIPTION = ?, SORT_ORDER = ?, CREATED_AT = ? WHERE ID = ? ";
        int[] result = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                int j = 0;
                AgentField item = list.get(i);
                ps.setString(++j, item.getAgentId());
                ps.setString(++j, item.getFieldName());
                ps.setString(++j, item.getFieldLabel());
                ps.setString(++j, item.getFieldType());
                ps.setString(++j, item.getDateFormat());
                ps.setString(++j, item.getEnumOptionsJson());
                ps.setBoolean(++j, item.isRequired());
                ps.setString(++j, item.getDescription());
                ps.setObject(++j, item.getSortOrder());
                ps.setTimestamp(++j, item.getCreatedAt() != null ? Timestamp.valueOf(item.getCreatedAt()) : 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_AGENT_FIELDS 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 AgentField selectById(String id) {
        String sql = "SELECT * FROM AI_AGENT_FIELDS WHERE ID = ? ";
        try {
            return jdbcTemplate.queryForObject(sql, new AgentFieldRowMapper(), id);
        } catch (Exception e) {
            LogHelper.error(this,this.getClass().getName(),e);
            return null;
        }
    }

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

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

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

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

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

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

    @Override
    public List<AgentField> findAllByAgentIdOrderBySortOrderAsc(String agentId) {
        AgentFieldCriteria criteria = new AgentFieldCriteria();
        criteria.setAgentId(agentId);
        List<AgentField> fields = selectByCriteria(criteria);
        if (fields == null) {
            return List.of();
        }
        return fields.stream()
                .sorted((left, right) -> Integer.compare(left.getSortOrder(), right.getSortOrder()))
                .toList();
    }

    @Override
    public void deleteByAgentId(String agentId) {
        findAllByAgentIdOrderBySortOrderAsc(agentId).forEach(field -> delete(field.getId()));
    }

    /**
     * RowMapper
     */
    private class AgentFieldRowMapper implements RowMapper<AgentField> {
        @Override
        public AgentField mapRow(ResultSet rs, int i) throws SQLException {
            return new AgentField(
                    rs.getString("ID"),
                    rs.getString("AGENT_ID"),
                    rs.getString("FIELD_NAME"),
                    rs.getString("FIELD_LABEL"),
                    rs.getString("FIELD_TYPE"),
                    rs.getString("DATE_FORMAT"),
                    rs.getString("ENUM_OPTIONS"),
                    rs.getObject("REQUIRED") != null ? rs.getBoolean("REQUIRED") : false,
                    rs.getString("DESCRIPTION"),
                    rs.getObject("SORT_ORDER") != null ? rs.getInt("SORT_ORDER") : 0,
                    rs.getTimestamp("CREATED_AT").toLocalDateTime()
            );
        }
    }

    /**
     * 创建查询条件
     */
    private Map<String, Object> createCriteriaSql(AgentFieldCriteria criteria) {
        Map<String, Object> andMap = new LinkedHashMap<>();
        if (criteria == null)
            return andMap;
        //if (criteria.byId())
        //    andMap.put(criteria.getId() == null ? " T_Id IS NULL " : " T_Id = ? ", criteria.getId());

        //智能体id
        if (criteria.byAgentId())
            andMap.put(criteria.getAgentId() == null ? " AGENT_ID IS NULL " : " AGENT_ID = ? ", criteria.getAgentId());
        //字段英文名，如 leave_start_date
        if (criteria.byFieldName())
            andMap.put(criteria.getFieldName() == null ? " FIELD_NAME IS NULL " : " FIELD_NAME = ? ", criteria.getFieldName());
        //字段英文名，如 leave_start_date（LIKE）
        if (criteria.byFieldNameContain())
            andMap.put(" FIELD_NAME LIKE ? ", "%" + criteria.getFieldNameContain() + "%");
        //字段中文名，如 请假开始日期
        if (criteria.byFieldLabel())
            andMap.put(criteria.getFieldLabel() == null ? " FIELD_LABEL IS NULL " : " FIELD_LABEL = ? ", criteria.getFieldLabel());
        //字段中文名，如 请假开始日期（LIKE）
        if (criteria.byFieldLabelContain())
            andMap.put(" FIELD_LABEL LIKE ? ", "%" + criteria.getFieldLabelContain() + "%");
        //text / number / date / datetime / enum / boolean
        if (criteria.byFieldType())
            andMap.put(criteria.getFieldType() == null ? " FIELD_TYPE IS NULL " : " FIELD_TYPE = ? ", criteria.getFieldType());
        //是否必填
        if (criteria.byRequired())
            andMap.put(criteria.getRequired() == null ? " REQUIRED IS NULL " : " REQUIRED = ? ", criteria.getRequired());
        return andMap;
    }

}
