package com.infoepoch.pms.dispatchassistant.infractructure.basic.todo;

import com.infoepoch.pms.dispatchassistant.common.enums.EnumUtils;
import com.infoepoch.pms.dispatchassistant.common.exception.ValidationException;
import com.infoepoch.pms.dispatchassistant.common.utils.DateTool;
import com.infoepoch.pms.dispatchassistant.common.utils.OracleUtils;
import com.infoepoch.pms.dispatchassistant.domain.basic.todo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Repository;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 待办Repository
 */
@Repository
public class TodoRepository implements ITodoRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * @Description: 查询条件转换
     * @Param: [criteria]
     * @Author: zhangyd
     */
    private Map<String, Object> createCriteriaSql(TodoCriteria criteria) {
        Map<String, Object> andMap = new LinkedHashMap<>();
        // ActionFlag
        if (criteria.andMap.containsKey("ActionFlag"))
            andMap.put(criteria.andMap.get("ActionFlag") == null ? " TD_ACTION_FLAG IS ? " : " TD_ACTION_FLAG = ? ", criteria.andMap.get("ActionFlag"));
        // SendFlag
        if (criteria.andMap.containsKey("SendFlag"))
            andMap.put(criteria.andMap.get("SendFlag") == null ? " TD_SEND_FLAG IS ? " : " TD_SEND_FLAG = ? ", criteria.andMap.get("SendFlag"));
        // ProcessId
        if (criteria.andMap.containsKey("ProcessId"))
            andMap.put(criteria.andMap.get("ProcessId") == null ? " TD_PROCESS_ID IS ? " : " TD_PROCESS_ID = ? ", criteria.andMap.get("ProcessId"));
        // DomainId
        if (criteria.andMap.containsKey("DomainId"))
            andMap.put(criteria.andMap.get("DomainId") == null ? " TD_DOMAIN_ID IS ? " : " TD_DOMAIN_ID = ? ", criteria.andMap.get("DomainId"));
        // Id
        if (criteria.andMap.containsKey("Id"))
            andMap.put(criteria.andMap.get("Id") == null ? " TD_ID IS ? " : " TD_ID = ? ", criteria.andMap.get("Id"));
        // Receiver
        if (criteria.andMap.containsKey("Receiver"))
            andMap.put(criteria.andMap.get("Receiver") == null ? " TD_RECEIVER IS ? " : " TD_RECEIVER = ? ", criteria.andMap.get("Receiver"));
        // DocumentType
        if (criteria.andMap.containsKey("DocumentType"))
            andMap.put(criteria.andMap.get("DocumentType") == null ? " TD_DOCUMENT_TYPE IS ? " : " TD_DOCUMENT_TYPE = ? ", criteria.andMap.get("DocumentType"));
        // Drafter
        if (criteria.andMap.containsKey("Drafter"))
            andMap.put(criteria.andMap.get("Drafter") == null ? " TD_DRAFTER IS ? " : " TD_DRAFTER = ? ", criteria.andMap.get("Drafter"));
        // ActivityIdNotNull
        if (criteria.andMap.containsKey("ActivityIdNotNull"))
            andMap.put(" TD_ACTIVITY_ID IS NOT NULL AND TD_ACTIVITY_ID != ? ", "");
        // ProcessIdNotNull
        if (criteria.andMap.containsKey("ProcessIdNotNull"))
            andMap.put(" TD_ACTIVITY_ID IS NOT NULL AND TD_ACTIVITY_ID != ? ", "");
        // DocumentTypeList
        if (criteria.andMap.containsKey("DocumentTypeList"))
            andMap.put(" TD_DOCUMENT_TYPE IN ", criteria.andMap.get("DocumentTypeList"));
        // ActivityIdList
        if (criteria.andMap.containsKey("ActivityIdList"))
            andMap.put(" TD_ACTIVITY_ID IN ", criteria.andMap.get("ActivityIdList"));
        // Ids
        if (criteria.andMap.containsKey("Ids"))
            andMap.put(OracleUtils.placeholderIn("TD_ID", criteria.andMap.get("Ids")), criteria.andMap.get("Ids"));
        // Action
        if (criteria.andMap.containsKey("Action") && criteria.andMap.get("Action") != null) {
            if (Boolean.parseBoolean(criteria.andMap.get("Action").toString()))
                andMap.put(" TD_ACTION_TIME IS NOT null ", null);
            else
                andMap.put(" TD_ACTION_TIME IS null", null);
        }
        //存在用户接收人存（名称+部门）格式，用like查询
        if (criteria.andMap.containsKey("ReceiverName"))
            andMap.put(" TD_RECEIVER_NAME LIKE ? ", "%" + criteria.andMap.get("ReceiverName") + "%");
        // Stage
        if (criteria.andMap.containsKey("Stage")) {
            andMap.put(" TD_STAGE = ? ", criteria.andMap.get("Stage"));
        }
        // TitleContain
        if (criteria.andMap.containsKey("TitleContain"))
            andMap.put(" TD_TITLE LIKE ? ", "%" + criteria.andMap.get("TitleContain") + "%");

        if (criteria.byReceiverId())
            andMap.put(" TD_RECEIVER = ? ", criteria.getReceiverId());

        if (criteria.bySendDateStart() && criteria.getSendDateStart() != null) {
            andMap.put(" TD_SEND_TIME >= ? ", criteria.getSendDateStart());
        }

        if (criteria.bySendDateEnd() && criteria.getSendDateEnd() != null) {
            andMap.put(" TD_SEND_TIME < ? ", DateTool.getDateAddDay(criteria.getSendDateEnd(), 1));
        }
        return andMap;
    }

    /**
     * @Description: 查询转换
     * @Param:
     * @Author: zhangyd
     */
    public class TodoRowMapper implements RowMapper<Todo> {
        @Override
        public Todo mapRow(ResultSet rs, int i) throws SQLException {
            return new Todo(
                    rs.getString("TD_ID"),
                    rs.getString("TD_DOCUMENT_TYPE"),
                    rs.getString("TD_DOMAIN_ID"),
                    rs.getString("TD_PROCESS_ID"),
                    rs.getString("TD_ACTIVITY_ID"),
                    rs.getString("TD_STAGE"),
                    rs.getString("TD_DRAFTER"),
                    rs.getString("TD_DRAFTER_NAME"),
                    EnumUtils.getByValue(TodoType.class, rs.getInt("TD_TYPE")),
                    EnumUtils.getByValue(TodoLevel.class, rs.getInt("TD_LEVEL")),
                    rs.getString("TD_TITLE"),
                    rs.getString("TD_URL"),
                    rs.getTimestamp("TD_SEND_TIME"),
                    rs.getString("TD_SENDER"),
                    rs.getString("TD_SENDER_NAME"),
                    rs.getString("TD_RECEIVER"),
                    rs.getString("TD_RECEIVER_NAME"),
                    rs.getTimestamp("TD_ACTION_TIME"),
                    rs.getString("TD_ADDITIONAL_DATA"),
                    rs.getObject("TD_SYNC_STATUS") == null ? null : rs.getInt("TD_SYNC_STATUS"),
                    rs.getString("TD_URL_MOA")
            );
        }
    }

    @Override
    public void insert(Todo todo) {
        jdbcTemplate.update("INSERT INTO BAS_TODO (TD_ID, TD_DOCUMENT_TYPE, TD_DOMAIN_ID, TD_PROCESS_ID, TD_ACTIVITY_ID," +
                        "TD_STAGE, TD_DRAFTER, TD_DRAFTER_NAME, TD_TYPE, TD_LEVEL, TD_TITLE, TD_URL, TD_SEND_TIME," +
                        "TD_SENDER, TD_SENDER_NAME, TD_RECEIVER, TD_RECEIVER_NAME, TD_ACTION_TIME, TD_ADDITIONAL_DATA, TD_SYNC_STATUS," +
                        "TD_URL_MOA)" +
                        "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                todo.getId(), todo.getDocumentType(), todo.getDomainId(), todo.getProcessId(), todo.getActivityId(),
                todo.getStage(), todo.getDrafter(), todo.getDrafterName(), todo.getType().getValue(), todo.getLevel().getValue(),
                todo.getTitle(), todo.getUrl(), todo.getSendTime(), todo.getSender(), todo.getSenderName(), todo.getReceiver(),
                todo.getReceiverName(), todo.getActionTime(), todo.getAdditionalData(), todo.getSyncStatus(), todo.getUrlMoa());
    }

    @Override
    public void update(Todo todo) {
        String sql = "UPDATE BAS_TODO SET TD_DOCUMENT_TYPE = ?, TD_DOMAIN_ID = ?, TD_PROCESS_ID = ?, TD_ACTIVITY_ID = ?, TD_STAGE = ?, TD_DRAFTER = ?," +
                " TD_DRAFTER_NAME = ?, TD_TYPE = ?, TD_LEVEL = ?, TD_TITLE = ?, TD_URL = ?, TD_SEND_TIME = ?, TD_SENDER = ?, TD_SENDER_NAME = ?," +
                " TD_RECEIVER = ?, TD_RECEIVER_NAME = ?, TD_ACTION_TIME = ?, TD_ADDITIONAL_DATA = ?, TD_SYNC_STATUS = ?, TD_URL_MOA = ? WHERE TD_ID = ?";
        jdbcTemplate.update(sql,
                todo.getDocumentType(),
                todo.getDomainId(),
                todo.getProcessId(),
                todo.getActivityId(),
                todo.getStage(),
                todo.getDrafter(),
                todo.getDrafterName(),
                todo.getType().getValue(),
                todo.getLevel().getValue(),
                todo.getTitle(),
                todo.getUrl(),
                todo.getSendTime(),
                todo.getSender(),
                todo.getSenderName(),
                todo.getReceiver(),
                todo.getReceiverName(),
                todo.getActionTime(),
                todo.getAdditionalData(),
                todo.getSyncStatus(),
                todo.getUrlMoa(),
                todo.getId()
        );
    }

    /**
     * 更新
     *
     * @param todo
     */
    @Override
    public void updateAction(Todo todo) {
        jdbcTemplate.update("UPDATE BAS_TODO SET TD_TYPE = ?, TD_ACTION_TIME = ?, TD_URL = ?, TD_SYNC_STATUS = ? WHERE TD_ID = ?",
                todo.getType().getValue(), todo.getActionTime(), todo.getUrl(), todo.getSyncStatus(), todo.getId());
    }

    /**
     * 批量更新
     *
     * @param todoList
     */
    @Override
    public int[] batchUpdate(List<Todo> todoList) {
        String sql = "UPDATE BAS_TODO SET TD_DOCUMENT_TYPE = ?, TD_DOMAIN_ID = ?, TD_PROCESS_ID = ?, TD_ACTIVITY_ID = ?, TD_STAGE = ?, TD_DRAFTER = ?," +
                " TD_DRAFTER_NAME = ?, TD_TYPE = ?, TD_LEVEL = ?, TD_TITLE = ?, TD_URL = ?, TD_SEND_TIME = ?, TD_SENDER = ?, TD_SENDER_NAME = ?," +
                " TD_RECEIVER = ?, TD_RECEIVER_NAME = ?, TD_ACTION_TIME = ?, TD_ADDITIONAL_DATA = ?, TD_SYNC_STATUS = ?, TD_URL_MOA = ? WHERE TD_ID = ?";
        int[] result = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                Todo item = todoList.get(i);
                ps.setString(1, item.getDocumentType());
                ps.setString(2, item.getDomainId());
                ps.setString(3, item.getProcessId());
                ps.setString(4, item.getActivityId());
                ps.setString(5, item.getStage());
                ps.setString(6, item.getDrafter());
                ps.setString(7, item.getDrafterName());
                ps.setInt(8, item.getType().getValue());
                ps.setInt(9, item.getLevel().getValue());
                ps.setString(10, item.getTitle());
                ps.setString(11, item.getUrl());
                ps.setTimestamp(12, item.getSendTime() == null ? null : new Timestamp(item.getSendTime().getTime()));
                ps.setString(13, item.getSender());
                ps.setString(14, item.getSenderName());
                ps.setString(15, item.getReceiver());
                ps.setString(16, item.getReceiverName());
                ps.setTimestamp(17, item.getActionTime() == null ? null : new Timestamp(item.getActionTime().getTime()));
                ps.setString(18, item.getAdditionalData());
                ps.setInt(19, item.getSyncStatus());
                ps.setString(20, item.getUrlMoa());
                ps.setString(21, item.getId());
            }

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

    @Override
    public void deleteById(String id) {
        jdbcTemplate.update("DELETE FROM BAS_TODO WHERE TD_ID = ? ", id);
    }


    @Override
    public Todo selectById(String id) {
        String sb = "SELECT * FROM BAS_TODO WHERE TD_ID = ?";
        try {
            return jdbcTemplate.queryForObject(sb, new TodoRowMapper(), id);
        } catch (DataAccessException ex) {
            return null;
        }
    }

    @Override
    public List<Todo> selectByProcess(String processId) {
        String sb = "SELECT * FROM BAS_TODO WHERE TD_PROCESS_ID = ? ";
        try {
            return jdbcTemplate.query(sb, new TodoRowMapper(), processId);
        } catch (DataAccessException e) {
            return new ArrayList<Todo>();
        }
    }

    @Override
    public List<String> selectDocumentTypes() {
        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet("SELECT DISTINCT TD_DOCUMENT_TYPE FROM BAS_TODO ORDER BY TD_DOCUMENT_TYPE");
        List<String> list = new ArrayList<>();
        while (sqlRowSet.next()) {
            list.add(sqlRowSet.getString("TD_DOCUMENT_TYPE"));
        }
        return list;
    }


    @Override
    public int selectCount(TodoCriteria criteria) {
        StringBuffer sb = new StringBuffer("SELECT COUNT(*) FROM BAS_TODO");
        List<Object> list = OracleUtils.combinationSql(sb, createCriteriaSql(criteria));
        try {
            return jdbcTemplate.queryForObject(sb.toString(), list.toArray(), Integer.class);
        } catch (DataAccessException ex) {
            return 0;
        }
    }

    @Override
    public List<Todo> selectByPage(int pageIndex, int pageSize, TodoCriteria criteria) {
        StringBuffer sb = new StringBuffer("SELECT * FROM BAS_TODO");
        List<Object> list = new ArrayList<>();
        //待办以发送时间排序，已办以处理时间排序
        if (criteria.andMap.containsKey("Action") && criteria.andMap.get("Action") != null && Boolean.parseBoolean(criteria.andMap.get("Action").toString()))
            list = OracleUtils.combinationSql(sb, createCriteriaSql(criteria), pageIndex, pageSize, "TD_ACTION_TIME");
        else
            list = OracleUtils.combinationSql(sb, createCriteriaSql(criteria), pageIndex, pageSize, "TD_SEND_TIME");
        try {
            return jdbcTemplate.query(sb.toString(), list.toArray(), new TodoRowMapper());
        } catch (DataAccessException e) {
            return new ArrayList<Todo>();
        }
    }

    /**
     * 查询
     *
     * @param criteria
     */
    @Override
    public List<Todo> selectByCriteria(TodoCriteria criteria) {
        StringBuffer sb = new StringBuffer("SELECT * FROM BAS_TODO");
        List<Object> list = new ArrayList<>();
        //待办以发送时间排序，已办以处理时间排序
        if (criteria.andMap.containsKey("Action") && criteria.andMap.get("Action") != null && Boolean.parseBoolean(criteria.andMap.get("Action").toString()))
            list = OracleUtils.combinationSql(sb, createCriteriaSql(criteria), "TD_ACTION_TIME", true);
        else
            list = OracleUtils.combinationSql(sb, createCriteriaSql(criteria), "TD_SEND_TIME", true);
        try {
            return jdbcTemplate.query(sb.toString(), list.toArray(), new TodoRowMapper());
        } catch (DataAccessException e) {
            return new ArrayList<Todo>();
        }
    }

    @Override
    public void read(String todoId) {
        try {
            //内网的 待阅转已阅的时候，将 td_sync_status的状态从 1已同步转为0待同步。
            String sql = "UPDATE BAS_TODO SET TD_ACTION_TIME = sysdate WHERE TD_ACTION_TIME IS NULL AND TD_ID = ?";
            jdbcTemplate.update(sql, todoId);
        } catch (Exception e) {
            throw new ValidationException("待阅更新为已阅失败");
        }
    }
}
