package com.infoepoch.pms.agent.infractructure.basic.organization;

import com.infoepoch.pms.agent.common.utils.OracleUtils;
import com.infoepoch.pms.agent.domain.baisc.organization.IOrganizationRepository;
import com.infoepoch.pms.agent.domain.baisc.organization.Organization;
import com.infoepoch.pms.agent.domain.baisc.organization.OrganizationCriteria;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
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.util.*;
import java.util.stream.Collectors;

/**
 * @Description 组织机构
 * @Author lxd
 **/
@Repository
public class OrganizationRepository implements IOrganizationRepository {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Override
    public List<Organization> selectByCriteriaPage(OrganizationCriteria criteria, int pageIndex, int pageSize) {
        StringBuffer buffer = new StringBuffer("SELECT * FROM BAS_ORGANIZATION ");
        List<Object> list = OracleUtils.combinationSql(buffer, createCriteriaSql(criteria), pageIndex, pageSize, "BO_DISPLAY_ORDER,BO_ID", false);
        try {
            return jdbcTemplate.query(buffer.toString(), list.toArray(), new OrganizationRowMapper());
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    @Override
    public List<Organization> selectByCriteriaPage(OrganizationCriteria criteria, int pageIndex, int pageSize, String orderBy, boolean isDesc) {
        StringBuffer buffer = new StringBuffer("SELECT * FROM BAS_ORGANIZATION ");
        List<Object> list = OracleUtils.combinationSql(buffer, createCriteriaSql(criteria), pageIndex, pageSize, orderBy, isDesc);
        try {
            return jdbcTemplate.query(buffer.toString(), list.toArray(), new OrganizationRowMapper());
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    @Override
    public int selectCountByCriteria(OrganizationCriteria criteria) {
        StringBuffer buffer = new StringBuffer("SELECT COUNT(*) FROM BAS_ORGANIZATION ");
        List<Object> list = OracleUtils.combinationSql(buffer, createCriteriaSql(criteria));
        return jdbcTemplate.queryForObject(buffer.toString(), list.toArray(), int.class);
    }

    @Override
    public List<Organization> selectByCriteria(OrganizationCriteria criteria) {
        StringBuffer buffer = new StringBuffer("SELECT * FROM BAS_ORGANIZATION ");
        List<Object> list = OracleUtils.combinationSql(buffer, createCriteriaSql(criteria));
        // START WITH 不能放到andMap中
        if (StringUtils.isNotBlank(criteria.getTreeParentId())) {
            buffer.append(" START WITH BO_ID = ? CONNECT BY PRIOR BO_ID = BO_PARENT_ID");
            list.add(criteria.getTreeParentId());
        }else if (CollectionUtils.isNotEmpty(criteria.getTreeParentIds())){
            String placeholders = criteria.getTreeParentIds()
                    .stream()
                    .map(id -> "?")
                    .collect(Collectors.joining(", "));
            buffer.append(" START WITH BO_ID in (").append(placeholders).append(") CONNECT BY PRIOR BO_ID = BO_PARENT_ID");
            list.addAll(criteria.getTreeParentIds());
        }
        buffer.append(" ORDER BY BO_DISPLAY_ORDER,BO_ID");
        try {
            return jdbcTemplate.query(buffer.toString(), list.toArray(), new OrganizationRowMapper());
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    private Map<String, Object> createCriteriaSql(OrganizationCriteria criteria) {
        Map<String, Object> andMap = new LinkedHashMap<>();
        if (criteria == null)
            return andMap;
        if (criteria.byShortName()) {
            andMap.put(criteria.getShortName() == null ? " BO_SHORT_NAME IS NULL" : " BO_SHORT_NAME = ? ", criteria.getShortName());
        }
        if (criteria.byShortNameContain()) {
            andMap.put(" BO_SHORT_NAME LIKE ? ", "%" + criteria.getShortNameContain() + "%");
        }
        if (StringUtils.isNotBlank(criteria.getNameContain())) {
            andMap.put(" BO_NAME LIKE ? ", "%" + criteria.getNameContain() + "%");
        }
        if (CollectionUtils.isNotEmpty(criteria.getOrgIdList())) {
            andMap.put(OracleUtils.placeholderIn("BO_ID", criteria.getOrgIdList()), criteria.getOrgIdList());
        }
        if (criteria.getSearchThreeFlag()) {
            String builder = "(" +
                    "BO_ID IN (SELECT BO_ID FROM BAS_ORGANIZATION WHERE BO_PARENT_ID = 0)" +
                    "OR BO_ID IN (SELECT BO_ID FROM BAS_ORGANIZATION WHERE BO_PARENT_ID IN (SELECT BO_ID FROM BAS_ORGANIZATION WHERE BO_PARENT_ID = 0))" +
                    "OR BO_ID IN (SELECT BO_ID FROM BAS_ORGANIZATION WHERE BO_PARENT_ID IN (SELECT BO_ID FROM BAS_ORGANIZATION WHERE BO_PARENT_ID IN (SELECT BO_ID FROM BAS_ORGANIZATION WHERE BO_PARENT_ID = 0)))" +
                    ")";
            andMap.put(builder, null);
        }
        if (criteria.getDisabledFlag() != null) {
            andMap.put(" BO_DISABLED = ? ", criteria.getDisabledFlag());
        }
        if (CollectionUtils.isNotEmpty(criteria.getOaOrgCodeList())) {
            andMap.put(OracleUtils.placeholderIn("BO_OA_ORG_CODE", criteria.getOaOrgCodeList()), criteria.getOaOrgCodeList());
        }
        // 组织级别
        if (criteria.getLevel() != null) {
            andMap.put(" BO_LEVEL = ? ", criteria.getLevel());
        }
        // 组织级别列表
        if (CollectionUtils.isNotEmpty(criteria.getLevelList())) {
            andMap.put(OracleUtils.placeholderIn("BO_LEVEL", criteria.getLevelList()), criteria.getLevelList());
        }
        // 父组织ID列表
        if (CollectionUtils.isNotEmpty(criteria.getParentIdList())) {
            andMap.put(OracleUtils.placeholderIn("BO_PARENT_ID", criteria.getParentIdList()), criteria.getParentIdList());
        }
        if (StringUtils.isNotEmpty(criteria.getParentId())){
            andMap.put(" BO_PARENT_ID = ? ", criteria.getParentId());
        }

        if (StringUtils.isNotBlank(criteria.getTreeParentId())) {
            andMap.put(" BO_ID IN (SELECT BO_ID FROM BAS_ORGANIZATION START WITH BO_ID = ? CONNECT BY PRIOR BO_ID = BO_PARENT_ID) ", criteria.getTreeParentId());
        }
        // 分公司ID
        if (StringUtils.isNotBlank(criteria.getCompanyId())) {
            andMap.put(" BO_ID IN (SELECT BO_ID FROM BAS_ORGANIZATION START WITH BO_ID = ? CONNECT BY PRIOR BO_ID = BO_PARENT_ID) ", criteria.getCompanyId());
        }
        return andMap;
    }

    private class OrganizationRowMapper implements RowMapper<Organization> {
        @Override
        public Organization mapRow(ResultSet rs, int rowNum) throws SQLException {
            return new Organization(
                    rs.getString("BO_ID"),
                    rs.getString("BO_NAME"),
                    rs.getString("BO_SHORT_NAME"),
                    rs.getBoolean("BO_DISABLED"),
                    rs.getString("BO_DESCRIPTION"),
                    rs.getString("BO_OA_ORG_CODE"),
                    rs.getString("BO_HR_ORG_CODE"),
                    rs.getString("BO_PARENT_ID"),
                    rs.getString("BO_DISPLAY_ORDER"),
                    rs.getString("BO_PARENT_ORG_CODE"),
                    rs.getObject("BO_LEVEL") == null ? null : rs.getInt("BO_LEVEL")
            );
        }
    }

    /**
     * @Description: 根据父id查询
     * @Param: [parentId]
     * @Author: zhangyd
     */
    @Override
    public List<Organization> selectByParentId(String parentId) {
        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet("SELECT * FROM BAS_ORGANIZATION WHERE BO_PARENT_ID = ? ORDER BY BO_DISPLAY_ORDER,BO_ID", parentId);
        List<Organization> list = new ArrayList<>();
        while (sqlRowSet.next()) {
            list.add(convert(sqlRowSet));
        }
        return list;
    }

    @Override
    public List<Organization> selectByParentIdList(List<String> parentIdList) {
        StringBuffer buffer = new StringBuffer("SELECT * FROM BAS_ORGANIZATION");
        Map<String, Object> andMap = new HashMap<>();
        andMap.put(OracleUtils.placeholderIn("BO_PARENT_ID", parentIdList), parentIdList);
        List<Object> paramList = OracleUtils.combinationSql(buffer, andMap, "BO_DISPLAY_ORDER,BO_ID", false);
        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(buffer.toString(), paramList.toArray());
        List<Organization> list = new ArrayList<>();
        while (sqlRowSet.next()) {
            list.add(convert(sqlRowSet));
        }
        return list;
    }

    /**
     * @Description: 获取所有组织Map
     * @Param: []
     * @Author: zhangyd
     */
    @Override
    public Map<String, Organization> selectMapAll() {
        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet("SELECT * FROM BAS_ORGANIZATION ORDER BY BO_DISPLAY_ORDER,BO_ID");
        Map<String, Organization> map = new HashMap<>();
        while (sqlRowSet.next()) {
            map.put(sqlRowSet.getString("BO_ID"), convert(sqlRowSet));
        }
        return map;
    }

    @Override
    public List<Organization> selectAll() {
        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet("SELECT * FROM BAS_ORGANIZATION ORDER BY BO_DISPLAY_ORDER,BO_ID");
        List<Organization> list = new ArrayList<>();
        while (sqlRowSet.next()) {
            list.add(convert(sqlRowSet));
        }
        return list;
    }

    @Override
    public Organization selectById(String id) {
        String sql = "SELECT * FROM BAS_ORGANIZATION WHERE BO_ID= ?";
        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(sql, id);
        if (sqlRowSet.next()) {
            return convert(sqlRowSet);
        }
        return null;
    }

    @Override
    public List<Organization> selectByIds(List<String> ids) {
        if (CollectionUtils.isEmpty(ids))
            return new ArrayList<>();
        List<Organization> list = new ArrayList<>();
        StringBuffer sql = new StringBuffer("SELECT * FROM BAS_ORGANIZATION");
        Map<String, Object> andMap = new HashMap<>();
        andMap.put(OracleUtils.placeholderIn("BO_ID", ids), ids);
        List<Object> paramList = OracleUtils.combinationSql(sql, andMap, "BO_LEVEL,BO_DISPLAY_ORDER,BO_ID", false);
        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(sql.toString(), paramList.toArray());
        while (sqlRowSet.next()) {
            list.add(convert(sqlRowSet));
        }
        return list;
    }

    @Override
    public Organization selectByName(String name) {
        String sql = "SELECT * FROM BAS_ORGANIZATION WHERE BO_NAME = ?";
        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(sql, name);
        if (sqlRowSet.next()) {
            return convert(sqlRowSet);
        }

        return null;
    }

    @Override
    public Organization selectByShortName(String shortName) {
        String sql = "SELECT * FROM BAS_ORGANIZATION WHERE BO_SHORT_NAME = ?";
        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(sql, shortName);
        if (sqlRowSet.next()) {
            return convert(sqlRowSet);
        }

        return null;
    }

    @Override
    public void insert(Organization organization) {
        String sql = "INSERT INTO BAS_ORGANIZATION(BO_ID,BO_NAME,BO_SHORT_NAME,BO_DISABLED,BO_DESCRIPTION,BO_OA_ORG_CODE," +
                "BO_HR_ORG_CODE,BO_PARENT_ID,BO_DISPLAY_ORDER,BO_PARENT_ORG_CODE,BO_LEVEL) VALUES(?,?,?,?,?,?,?,?,?,?,?)";
        jdbcTemplate.update(sql,
                organization.getId(),
                organization.getName(),
                organization.getShortName(),
                organization.isDisabled(),
                organization.getDescription(),
                organization.getOaOrgCode(),
                organization.getHrOrgCode(),
                organization.getpId(),
                organization.getDisplayOrder(),
                organization.getParentOrgCode(),
                organization.getLevel()
        );
    }

    @Override
    public void batchInsert(List<Organization> organizationList) {
        String sql = "INSERT INTO BAS_ORGANIZATION(BO_ID,BO_NAME,BO_SHORT_NAME,BO_DISABLED,BO_DESCRIPTION,BO_OA_ORG_CODE," +
                "BO_HR_ORG_CODE,BO_PARENT_ID,BO_DISPLAY_ORDER,BO_PARENT_ORG_CODE,BO_LEVEL) VALUES(?,?,?,?,?,?,?,?,?,?,?)";
        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                Organization organization = organizationList.get(i);
                int j = 0;
                ps.setString(++j, organization.getId());
                ps.setString(++j, organization.getName());
                ps.setString(++j, organization.getShortName());
                ps.setObject(++j, organization.isDisabled());
                ps.setString(++j, organization.getDescription());
                ps.setString(++j, organization.getOaOrgCode());
                ps.setString(++j, organization.getHrOrgCode());
                ps.setString(++j, organization.getpId());
                ps.setString(++j, organization.getDisplayOrder());
                ps.setString(++j, organization.getParentOrgCode());
                ps.setObject(++j, organization.getLevel());
            }

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

    @Override
    public void update(Organization organization) {
        String sql = "UPDATE BAS_ORGANIZATION SET BO_NAME = ?,BO_SHORT_NAME = ?,BO_DISABLED = ?,BO_DESCRIPTION = ?,BO_OA_ORG_CODE = ?," +
                "BO_HR_ORG_CODE = ?,BO_PARENT_ID = ?,BO_DISPLAY_ORDER = ?,BO_PARENT_ORG_CODE = ?, BO_LEVEL = ? WHERE BO_ID = ?";
        jdbcTemplate.update(sql,
                organization.getName(),
                organization.getShortName(),
                organization.isDisabled(),
                organization.getDescription(),
                organization.getOaOrgCode(),
                organization.getHrOrgCode(),
                organization.getpId(),
                organization.getDisplayOrder(),
                organization.getParentOrgCode(),
                organization.getLevel(),
                organization.getId()
        );
    }

    @Override
    public void batchUpdate(List<Organization> organizationList) {
        String sql = "UPDATE BAS_ORGANIZATION SET BO_NAME = ?,BO_SHORT_NAME = ?,BO_DISABLED = ?,BO_DESCRIPTION = ?,BO_OA_ORG_CODE = ?," +
                "BO_HR_ORG_CODE = ?,BO_PARENT_ID = ?,BO_DISPLAY_ORDER = ?,BO_PARENT_ORG_CODE = ?, BO_LEVEL = ? WHERE BO_ID = ?";
        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                Organization organization = organizationList.get(i);
                int j = 0;
                ps.setString(++j, organization.getName());
                ps.setString(++j, organization.getShortName());
                ps.setObject(++j, organization.isDisabled());
                ps.setString(++j, organization.getDescription());
                ps.setString(++j, organization.getOaOrgCode());
                ps.setString(++j, organization.getHrOrgCode());
                ps.setString(++j, organization.getpId());
                ps.setString(++j, organization.getDisplayOrder());
                ps.setString(++j, organization.getParentOrgCode());
                ps.setObject(++j, organization.getLevel());
                ps.setString(++j, organization.getId());
            }

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

    @Override
    public void batchUpdateLevel(List<Organization> organizationList) {
        String sql = "UPDATE BAS_ORGANIZATION SET BO_LEVEL = ? WHERE BO_ID = ? ";
        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                Organization organization = organizationList.get(i);
                int j = 0;
                ps.setObject(++j, organization.getLevel());
                ps.setString(++j, organization.getId());
            }

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

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

    @Override
    public Organization selectByOaOrgCode(String oaOrgCode) {
        String sql = "SELECT * FROM BAS_ORGANIZATION WHERE BO_OA_ORG_CODE = ?";
        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(sql, oaOrgCode);
        if (sqlRowSet.next()) {
            return convert(sqlRowSet);
        }
        return null;
    }

    private Organization convert(SqlRowSet sqlRowSet) {
        return new Organization(
                sqlRowSet.getString("BO_ID")
                , sqlRowSet.getString("BO_NAME")
                , sqlRowSet.getString("BO_SHORT_NAME")
                , sqlRowSet.getBoolean("BO_DISABLED")
                , sqlRowSet.getString("BO_DESCRIPTION")
                , sqlRowSet.getString("BO_OA_ORG_CODE")
                , sqlRowSet.getString("BO_HR_ORG_CODE")
                , sqlRowSet.getString("BO_PARENT_ID")
                , sqlRowSet.getString("BO_DISPLAY_ORDER"),
                sqlRowSet.getString("BO_PARENT_ORG_CODE"),
                sqlRowSet.getObject("BO_LEVEL") == null ? null : sqlRowSet.getInt("BO_LEVEL")
        );
    }
}
