package com.infoepoch.pms.dispatchassistant.domain.oa;

import com.infoepoch.pms.dispatchassistant.common.constant.StoreKeys;
import com.infoepoch.pms.dispatchassistant.common.exception.ValidationException;
import com.infoepoch.pms.dispatchassistant.common.utils.DateTool;
import com.infoepoch.pms.dispatchassistant.common.utils.JsonUtils;
import com.infoepoch.pms.dispatchassistant.domain.basic.store.KeyValueStoreService;
import com.infoepoch.pms.dispatchassistant.domain.basic.user.UserSyncService;
import com.infoepoch.pms.dispatchassistant.domain.oa.account.*;
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.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.xml.ws.BindingProvider;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class OaUserService {

    private final static Logger logger = LoggerFactory.getLogger(OaUserService.class);

    @Autowired
    private KeyValueStoreService keyValueStoreService;
    @Autowired
    private UserSyncService userSyncService;

    @Autowired
    private IOaRepository oaRepository;

    /**
     * 定时同步
     *
     * @param startLastUpdateDate 起始时间
     * @param endLastUpdateDate   截至时间
     */
    @Async
    public void scheduleSyncOaEmployee(Date startLastUpdateDate, Date endLastUpdateDate) {
        syncOaEmployee(startLastUpdateDate, endLastUpdateDate, null);
    }

    /**
     * 同步OA用户信息
     *
     * @param startLastUpdateDate 起始时间
     * @param endLastUpdateDate   截至时间
     * @param employeeNumber      员工编码
     */
    public void syncOaEmployee(Date startLastUpdateDate, Date endLastUpdateDate, String employeeNumber) {
        if (StringUtils.isBlank(employeeNumber)) {
            if (startLastUpdateDate == null || endLastUpdateDate == null) {
                throw new ValidationException("员工编码为空时，起始时间和截至时间不能为空");
            }
        } else {
            startLastUpdateDate = DateTool.getDate("2020-01-01");
            endLastUpdateDate = new Date();
        }
        URL url = null;
        try {
            url = new URL(keyValueStoreService.queryValueByKey(StoreKeys.OA_EMPLOYEE_SYNC_URL));
        } catch (MalformedURLException e) {
            logger.error("获取OA员工同步地址失败");
        }
        syncOaEmployeeStart(startLastUpdateDate, endLastUpdateDate, employeeNumber, url);
    }

    /**
     * 同步接口开始
     *
     * @param startLastUpdateDate 起始时间
     * @param endLastUpdateDate   截至时间
     * @param employeeNumber      员工编码
     * @param url                 同步地址
     */
    private void syncOaEmployeeStart(Date startLastUpdateDate, Date endLastUpdateDate, String employeeNumber, URL url) {
        // 先查询一次，获取总记录数
        SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvResponse response = getSyncOaEmployeeResponse(1, -1, startLastUpdateDate, endLastUpdateDate, employeeNumber, url);
        if (response == null) {
            throw new ValidationException("获取OA员工同步响应数据失败");
        }
        int totalRecord = getTotalRecord(response);
        int totalPage = getTotalPage(response);
        if (totalRecord > 0) {
            for (int currentPage = 1; currentPage <= totalPage; currentPage++) {
                syncOaEmployeeExecute(currentPage, totalRecord, startLastUpdateDate, endLastUpdateDate, employeeNumber, url);
            }
        }
    }

    /**
     * 同步接口执行
     *
     * @param currentPage         当前页码
     * @param totalRecord         总记录数
     * @param startLastUpdateDate 起始时间
     * @param endLastUpdateDate   截至时间
     * @param employeeNumber      员工编码
     * @param url                 同步地址
     */
    private void syncOaEmployeeExecute(int currentPage, int totalRecord, Date startLastUpdateDate, Date endLastUpdateDate, String employeeNumber, URL url) {
        SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvResponse response = getSyncOaEmployeeResponse(currentPage, totalRecord, startLastUpdateDate, endLastUpdateDate, employeeNumber, url);
        List<SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvOutputItem> itemList = getSyncDataList(response);
        if (CollectionUtils.isEmpty(itemList))
            return;
        if (StringUtils.isBlank(employeeNumber)) {
            // 如果查询条件中的员工编号为空，重复调用更新用户的单个更新方法
            List<String> employeeNumberList = itemList.stream().map(SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvOutputItem::getEMPLOYEENUMBER).distinct().collect(Collectors.toList());
            for (String number : employeeNumberList) {
                syncOaEmployeeStart(startLastUpdateDate, endLastUpdateDate, number, url);
            }
        } else {
            // 查询条件中有员工编码，调用用户信息保存方法
            saveSingleEmployeeData(itemList);
        }
    }

    /**
     * 保存单个用户信息（会删除原本的用户信息后重新插入）
     *
     * @param itemList 同步数据列表
     */
    public void saveSingleEmployeeData(List<SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvOutputItem> itemList) {
        if (CollectionUtils.isNotEmpty(itemList)) {
            try {
                //保存单个用户信息（会删除原本的用户信息后重新插入）
                oaRepository.batchInsertEmployeeSingle(itemList);
            } catch (Exception e) {
                throw new ValidationException("保存oa用户信息异常！", e);
            }
            // 用户信息同步到BAS_USER
            userSyncService.userSyncForPmsSingle(itemList);
        } else {
            logger.info("oa用户信息为空。");
        }
    }

    /**
     * 获取接口返回对象
     *
     * @param currentPage         当前页码
     * @param totalRecord         总记录数量
     * @param startLastUpdateDate 开始时间
     * @param endLastUpdateDate   结束时间
     * @param employeeNumber      员工编号
     * @param url                 请求地址
     * @return 接口返回数据对象
     */
    private SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvResponse getSyncOaEmployeeResponse(int currentPage, int totalRecord, Date startLastUpdateDate, Date endLastUpdateDate, String employeeNumber, URL url) {
        long start = System.currentTimeMillis();
        SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrv_Service service = new SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrv_Service(url);
        SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrv port = service.getSBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvPort();
        BindingProvider bindingProvider = (BindingProvider) port;
        bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url.toString());
        SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvRequest request = makeRequest(currentPage, totalRecord, startLastUpdateDate, endLastUpdateDate, employeeNumber);
        logger.info("调用接口获取oa用户信息，请求参数：{}", JsonUtils.objectToJson(request));
        SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvResponse response = port.process(request);
        long end = System.currentTimeMillis();
        logger.info("通过接口拉取oa数据耗时{}s", (end - start) / 1000);
        logger.info("调用接口获取oa用户信息，响应数据：{}", JsonUtils.objectToJson(response));
        if ("Y".equals(response.getErrorFlag())) {
            return response;
        } else {
            logger.info("调用接口获取oa用户信息失败，错误信息：{}", response.getErrorMessage());
            return null;
        }
    }

    /**
     * 获取接口返回数据列表
     *
     * @param response 接口返回数据对象
     * @return 接口数据列表
     */
    private List<SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvOutputItem> getSyncDataList(SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvResponse response) {
        if ("Y".equals(response.getErrorFlag())) {
            if (response.getSBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvOutputCollection() != null) {
                SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvOutputCollection collection = response.getSBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvOutputCollection();
                if (collection != null)
                    return collection.getSBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvOutputItem();
            }
        }
        return null;
    }

    /**
     * 获取总记录数量
     *
     * @param response 接口返回数据对象
     * @return 总记录数
     */
    private int getTotalRecord(SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvResponse response) {
        if ("Y".equals(response.getErrorFlag())) {
            return response.getTOTALRECORD().intValue();
        }
        return -1;
    }

    /**
     * 获取总页码
     *
     * @param response 接口返回数据对象
     * @return 总页码
     */
    private int getTotalPage(SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvResponse response) {
        if ("Y".equals(response.getErrorFlag())) {
            return response.getTOTALPAGE().intValue();
        }
        return -1;
    }

    /**
     * 获取当前页码
     *
     * @param response 接口返回数据对象
     * @return 当前页码
     */
    private int getCurrentPage(SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvResponse response) {
        if ("Y".equals(response.getErrorFlag())) {
            return response.getCURRENTPAGE().intValue();
        }
        return -1;
    }

    /**
     * 创建接口请求体对象
     *
     * @param totalRecord         总记录数
     * @param currentPage         当前页码
     * @param startLastUpdateDate 起始最新更新日期
     * @param endLastUpdateDate   结束最新更新日期
     * @param employeeNumber      员工编号
     * @return 接口请求体对象
     */
    private SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvRequest makeRequest(int currentPage, int totalRecord, Date startLastUpdateDate, Date endLastUpdateDate, String employeeNumber) {
        MsgHeader msgheader = new MsgHeader();
        msgheader.setSOURCESYSTEMID("EPMS");
        msgheader.setSOURCESYSTEMNAME("江苏移动工程项目管理系统");
        msgheader.setPROVINCECODE("JS");
        msgheader.setCURRENTPAGE(new BigDecimal(currentPage));
        msgheader.setTOTALRECORD(new BigDecimal(totalRecord));
        msgheader.setPAGESIZE(new BigDecimal(100));
        msgheader.setUSERID("epms");
        msgheader.setUSERNAME("epms");
        msgheader.setSUBMITDATE(DateTool.dateToXmlDate(new Date()));
        msgheader.setENVIRONMENTNAME("ERP");
        SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvRequest request = new SBMDMMDMPageInquiryOAStandardEmpolyeeInfoSrvRequest();
        request.setMsgHeader(msgheader);
        if (startLastUpdateDate != null) {
            request.setSTARTLASTUPDATEDATE(DateTool.dateToXmlDate(startLastUpdateDate));
        }
        if (endLastUpdateDate != null) {
            request.setENDLASTUPDATEDATE(DateTool.dateToXmlDate(endLastUpdateDate));
        }
        if (StringUtils.isNotBlank(employeeNumber)) {
            request.setEMPLOYEENUMBER(employeeNumber);
        }
        return request;
    }

}
