package com.jpsoft.shinestar.modules.base.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import javax.annotation.Resource;

import cn.hutool.core.date.DateUtil;
import com.jpsoft.shinestar.config.WxConfig;
import com.jpsoft.shinestar.modules.base.entity.*;
import com.jpsoft.shinestar.modules.base.service.*;
import com.jpsoft.shinestar.modules.business.dto.UpdatePersonAttendanceDTO;
import com.jpsoft.shinestar.modules.business.service.WorkScheduleAttendanceService;
import com.jpsoft.shinestar.modules.common.utils.JwtUtil2;
import com.jpsoft.shinestar.modules.common.utils.WechatMessageUtil;
import com.jpsoft.shinestar.modules.workflow.entity.ProcinstActUser;
import com.jpsoft.shinestar.modules.workflow.entity.ProcinstActivity;
import com.jpsoft.shinestar.modules.workflow.service.ProcinstActUserService;
import com.jpsoft.shinestar.modules.workflow.service.ProcinstActivityService;
import com.jpsoft.shinestar.modules.workflow.service.ProcinstService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Hours;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.jpsoft.shinestar.modules.base.dao.BusinessOutDAO;
import com.github.pagehelper.Page;
import com.jpsoft.shinestar.modules.common.dto.Sort;
import com.github.pagehelper.PageHelper;

@Transactional(rollbackFor = Exception.class)
@Component(value = "businessOutService")
@Slf4j
public class BusinessOutServiceImpl implements BusinessOutService {
    @Resource(name = "businessOutDAO")
    private BusinessOutDAO businessOutDAO;

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Autowired
    private ApplicationExamineService applicationExamineService;

    @Autowired
    private PersonInfoService personInfoService;

    @Autowired
    private ProcinstActivityService procinstActivityService;

    @Autowired
    private ProcinstService procinstService;

    @Autowired
    private ApprovalConfigService approvalConfigService;

    @Autowired
    private WxConfig wxConfig;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    private ProcinstActUserService procinstActUserService;

    @Autowired
    private PersonPopedomService personPopedomService;

    @Autowired
    private CompanyInfoService companyInfoService;

    @Autowired
    private WorkScheduleAttendanceService workScheduleAttendanceService;

    @Override
    public BusinessOut get(String id) {
        // TODO Auto-generated method stub
        return businessOutDAO.get(id);
    }

    @Override
    public int insert(BusinessOut model) {
        // TODO Auto-generated method stub
        //model.setId(UUID.randomUUID().toString());

        return businessOutDAO.insert(model);
    }

    @Override
    public int update(BusinessOut model) {
        // TODO Auto-generated method stub
        return businessOutDAO.update(model);
    }

    @Override
    public int delete(String id) {
        // TODO Auto-generated method stub
        return businessOutDAO.delete(id);
    }

    @Override
    public boolean exist(String id) {
        // TODO Auto-generated method stub
        int count = businessOutDAO.exist(id);

        return count > 0 ? true : false;
    }

    @Override
    public List<BusinessOut> list() {
        // TODO Auto-generated method stub
        return businessOutDAO.list();
    }

    @Override
    public Page<BusinessOut> pageSearch(Map<String, Object> searchParams, int pageNumber, int pageSize, boolean count, List<Sort> sortList) {
        Page<BusinessOut> page = PageHelper.startPage(pageNumber, pageSize, count).doSelectPage(() -> {
            businessOutDAO.search(searchParams, sortList);
        });

        return page;
    }

    @Override
    public void approvalBusinessOut(PersonInfo personInfo, String ids, String status, String approvalContent,String nextApprovalId) throws Exception {
        List<String> idList = Arrays.asList(ids.split(","));

        if (idList.size() > 0) {
            for (String id : idList) {

                BusinessOut businessOut = get(id);

                String type = businessOut.getType();
                if ("1".equals(businessOut.getType())){
                    type = "2";
                }
                //申请人
                PersonPopedom personPopedom = personPopedomService.get(businessOut.getPersonPopedomId());
                PersonInfo person = personInfoService.get(personPopedom.getPersonId());

                if (!businessOut.getApprovalPersonPopedomId().equals(personInfo.getPopedom())) {
                    throw new Exception("无权审核");
                }
                String approvalPersonIdStr = businessOut.getApprovalPersonIdStr();
                String approvalStatusStr = businessOut.getApprovalStatusStr();
                String approvalTimeStr = businessOut.getApprovalTimeStr();
                String approvalContentStr = businessOut.getApprovalContentStr();


                //同意
                if ("1".equals(status)) {
                    List<PersonPopedom> personPopedomList = new ArrayList<>();

                    String companyId = "";
                    //申请人的公司
                    CompanyInfo companyInfo = companyInfoService.get(personPopedom.getCompanyId());

                    if (!"1".equals(companyInfo.getUnitType())) {

                        CompanyInfo parent = null;
                        int loopNum = 10;
                        int zIndex = 0;
                        if (org.apache.commons.lang3.StringUtils.isNotEmpty(companyInfo.getParentId())) {
                            parent = companyInfoService.get(companyInfo.getParentId());
                        }
                        while (parent != null && zIndex < loopNum) {
                            ApprovalConfig approvalConfig = approvalConfigService.findByCompanyIdAndType(companyInfo.getId(), type);
                            if (approvalConfig != null){
                                companyId = companyInfo.getId();
                                break;
                            }else if (org.apache.commons.lang3.StringUtils.isBlank(companyInfo.getParentId())) {
                                break;
                            }else {
                                parent = companyInfoService.get(parent.getParentId());
                                companyInfo = companyInfoService.get(companyInfo.getParentId());
                                zIndex++;
                            }
                        }

                        /*CompanyInfo parent = null;
                        int loopNum = 10;
                        int zIndex = 0;

                        if (StringUtils.isNotEmpty(companyInfo.getParentId())) {
                            parent = companyInfoService.get(companyInfo.getParentId());
                        }
                        while (parent != null && zIndex < loopNum) {

                            if ("1".equals(parent.getUnitType())) {
                                //如果是单位类型是公司或没有上级单位，则不再往上级查找
                                companyId = parent.getId();
                                break;
                            }
                            else if (StringUtils.isEmpty(companyInfo.getParentId())){
                                break;
                            }
                            else {
                                parent = companyInfoService.get(parent.getParentId());
                                zIndex++;
                            }
                        }*/


                    } else {
                        companyId = companyInfo.getId();
                    }

                    //默认审核层级
                    int level = 2;

                    if (StringUtils.isNotBlank(companyId)){

                        ApprovalConfig approvalConfig = approvalConfigService.findByCompanyIdAndType(companyId,type);
                        if (approvalConfig != null){
                            level = Integer.valueOf(approvalConfig.getLevel());
                        }

                    }

                    //计算当前审核的是第几级审批
                    int nowLevel = 1;
                    if (StringUtils.isNotBlank(approvalPersonIdStr)){
                        nowLevel = nowLevel + Arrays.asList(approvalPersonIdStr.split(",")).size();
                    }
                    //判断已审核人总数和需要审核级数
                    if (nowLevel<level){
                        List<PersonPopedom> dataList =  personPopedomService.findApprovalList(personInfo,null,null,null);
                        if (dataList.size()>0){
                            personPopedomList.add(dataList.get(0));
                        }
                    }

                        //判断审批人数量,审批人数据为0，审批流程走完
                        if (personPopedomList.size() == 0) {
                            businessOut.setApprovalTime(new Date());
                            businessOut.setStatus(status);
                            businessOut.setApprovalContent(approvalContent);
                            businessOut.setUpdateBy(personInfo.getPopedom());
                            businessOut.setUpdateTime(new Date());
                            update(businessOut);
                        }
                        //审批人数据不为0
                        else {
                            PersonPopedom personPopedom1 = personPopedomList.get(0);
                            if (StringUtils.isNotBlank(approvalPersonIdStr)) {
                                businessOut.setApprovalPersonIdStr(approvalPersonIdStr + "," + businessOut.getApprovalPersonPopedomId());
                                businessOut.setApprovalStatusStr(approvalStatusStr + "," + status);
                                businessOut.setApprovalTimeStr(approvalTimeStr + "," + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"));
                                businessOut.setApprovalContentStr(approvalContentStr + "," + approvalContent);
                            } else {
                                businessOut.setApprovalPersonIdStr(businessOut.getApprovalPersonPopedomId());
                                businessOut.setApprovalStatusStr(status);
                                businessOut.setApprovalTimeStr(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"));
                                businessOut.setApprovalContentStr(approvalContent);
                            }

                            businessOut.setApprovalPersonPopedomId(personPopedom1.getId());
                            businessOut.setStatus("0");
                            businessOut.setApprovalContent("");
                            businessOut.setApprovalTime(null);
                            update(businessOut);

                            new Thread(() -> {
                                PersonInfo approvalPerson = personInfoService.get(personPopedom1.getPersonId());

                                String typeN = null;
                                String url = null;
                                if ("1".equals(businessOut.getType())) {
                                    typeN = "外出";
                                    url = "master/egress/verifyInfo";
                                }
                                if ("3".equals(businessOut.getType())) {
                                    typeN = "出差";
                                    url = "master/businessTravel/verifyInfo";
                                }
                                String accessToken = JwtUtil2.createToken(jwtSecret, approvalPerson.getId() + "", DateTime.now().plusHours(30*24).toDate());
                                WechatMessageUtil.sendEvenMessage(approvalPerson.getOpenId(), "有一条新的" + typeN + "信息待审核", person.getName(), businessOut.getApprovalNo(), "前往处理", wxConfig.getPortalUrl() + url+"?id=" + businessOut.getId() + "&exchange=1&role_id=" + personPopedom1.getId() + "&token=" + accessToken, wxConfig.getAppId(), wxConfig.getAppSecret());

                            }).start();
                        }
               //     }
                }
                //拒绝
                if ("2".equals(status)) {
                    businessOut.setApprovalTime(new Date());
                    businessOut.setStatus(status);
                    businessOut.setApprovalContent(approvalContent);
                    businessOut.setUpdateBy(personInfo.getPopedom());
                    businessOut.setUpdateTime(new Date());
                    update(businessOut);

                }

                //通知申请人
                if (!"0".equals(businessOut.getStatus())) {
                    new Thread(() -> {
                        String firstMessage = "";
                        if ("1".equals(businessOut.getStatus())) {
                            firstMessage = "审核通过";
                            //延时队列处理人员工作状态
                            updatePersonWorkStatus(businessOut);

                        }
                        if ("2".equals(businessOut.getStatus())) {
                            firstMessage = "审核拒绝";
                        }


                        String url = null;
                        if ("1".equals(businessOut.getType())) {
                            url = "master/egress/info";
                        }
                        if ("3".equals(businessOut.getType())) {
                            url = "master/businessTravel/info";
                        }

                        String accessToken = JwtUtil2.createToken(jwtSecret, person.getId() + "", DateTime.now().plusHours(30*24).toDate());
                        WechatMessageUtil.sendExamine(person.getOpenId(), firstMessage, person.getName(), businessOut.getStatus(), businessOut.getStatusN(), businessOut.getTypeN(), "前往查看", wxConfig.getPortalUrl() +url +"?id=" + businessOut.getId() + "&exchange=1&role_id=" + personPopedom.getId() + "&token=" + accessToken, wxConfig.getAppId(), wxConfig.getAppSecret());

                    }).start();
                }


            }
        }
    }

    @Override
    public void updatePersonWorkStatus(BusinessOut businessOut) {
        try{
            PersonPopedom personPopedom = personPopedomService.get(businessOut.getPersonPopedomId());
            PersonInfo personInfo = personInfoService.get(personPopedom.getPersonId());

            Date now = new Date();

            //如果出差开始时间<=当前时间，说明是补出差记录，可能正在出差
            if (businessOut.getStartTime().compareTo(now) <=0){
                String workStatus = "";

                if ("1".equals(businessOut.getType())){
                    workStatus = "2";
                }
                else if ("3".equals(businessOut.getType())){
                    workStatus = "3";
                }

                personInfo.setWorkStatus(workStatus);
                personInfoService.update(personInfo);
            }
            else {
                //如果出差开始开始时间>当前时间，则延时修改状态
                long millisecond = DateUtil.betweenMs(now,businessOut.getStartTime());

                log.warn("创建延时队列修改工作状态，id："+businessOut.getId());

                rabbitTemplate.convertAndSend("businessOutDelayExchange", "businessOutSubmit",
                        businessOut.getId(), (message)->{
                            message.getMessageProperties().setHeader("x-delay",millisecond);
                            return message;
                        });
            }

            if(businessOut.getEndTime()!=null) {
                //如果出差结束时间<=当前时间，说明已出差结束
                if (businessOut.getEndTime().compareTo(now) <= 0) {
                    personInfo.setWorkStatus("1");
                    personInfoService.update(personInfo);
                } else {
                    //如果出差结束时间>当前时间，则延时修改状态
                    long millisecond = DateUtil.betweenMs(now, businessOut.getEndTime())+60000;

                    log.warn("创建延时队列修改工作状态，id：" + businessOut.getId());

                    rabbitTemplate.convertAndSend("businessOutDelayExchange", "businessOutSubmit",
                            businessOut.getId(), (message) -> {
                                message.getMessageProperties().setHeader("x-delay", millisecond);
                                return message;
                            });
                }
            }
        }catch (Exception ex){
            log.error(ex.getMessage(),ex);
        }
    }

    @Override
    public BusinessOut findLastActiveByPersonId(Long personId) {
        return businessOutDAO.findLastActiveByPersonId(personId);
    }
    @Override
    public List<BusinessOut> findByPersonPopedomAndEndTimeIsNull(String personPopedomId) {
        return businessOutDAO.findByPersonPopedomAndEndTimeIsNull(personPopedomId);
    }

    @Override
    public List<BusinessOut> findByPersonIdAndDate(Long personId, Date attendanceDate) {
        return businessOutDAO.findByPersonIdAndDate(personId, attendanceDate);
    }

    @Override
    public String submitBusiness(PersonPopedom personPopedom, String type, String destination, String startTime,String endTime,String days, String estimatedTime, String content,String formId,String ids,String draft) throws Exception {

        BusinessOut businessOut = new BusinessOut();
        if(StringUtils.isNotEmpty(ids)){
            businessOut=businessOutDAO.get(ids);

        }else{
            businessOut = new BusinessOut();
            businessOut.setId(UUID.randomUUID().toString());
        }
        businessOut.setPersonPopedomId(personPopedom.getId());
        businessOut.setType(type);
        businessOut.setStatus("-99");
        businessOut.setDestination(destination);
        businessOut.setStartTime(DateUtil.parse(startTime));
      //  businessOut.setEstimatedTime(estimatedTime);
        /*if (estimatedTime.contains(".")){
            Integer n  = estimatedTime.indexOf(".");
            String days = estimatedTime.substring(0,n);
            businessOut.setEstimatedDate(DateUtil.offsetDay(businessOut.getStartTime(),Integer.parseInt(days)));
            businessOut.setEstimatedDate(DateUtil.offsetHour(businessOut.getEstimatedDate(),12));
        }else {
            businessOut.setEstimatedDate(DateUtil.offsetDay(businessOut.getStartTime(),Integer.parseInt(estimatedTime)));
        }*/

    //    businessOut.setEndTime(businessOut.getEstimatedDate());
        businessOut.setEndTime(DateUtil.parse(endTime));
        businessOut.setEstimatedTime(days);
        businessOut.setEstimatedDate(DateUtil.parse(endTime));
        businessOut.setCreateTime(new Date());
        businessOut.setContent(content);

        //判断是否有重叠时间
        List<BusinessOut> businessOutList = findByGreaterEndTime(new Date(),personPopedom.getId());
        if (businessOutList.size()>0){
            for (BusinessOut businessOut1 : businessOutList){
                Date startTime1 = businessOut.getStartTime();
                Date endTime1 = businessOut.getEndTime();
                Date startTime2 = businessOut1.getStartTime();
                Date endTime2 = businessOut1.getEndTime();
                if (startTime1.compareTo(startTime2) <=0){
                    if (endTime1.compareTo(startTime2)>0){
                        throw new Exception("与其他出差记录的申请时间重叠");
                    }
                }
                if (startTime1.compareTo(startTime2)>0 && startTime1.compareTo(endTime2) <0 ){
                    throw new Exception("与其他出差记录的申请时间重叠");
                }


            }
        }

        if(StringUtils.isNotEmpty(ids)){
            update(businessOut);
        }else {
            insert(businessOut);
        }

        if ("1".equals(draft)) {
            String procInstId = procinstService.addProcInst(businessOut.getId(),  "出差", formId, personPopedom, null,null,null);

            businessOut.setProcinstId(procInstId);

            businessOut.setStatus("0");

            update(businessOut);

            ProcinstActivity procinstActivity = procinstActivityService.findByActivityIndexAndProcinstId(1, procInstId);

            if (procinstActivity != null) {
                List<ProcinstActUser> procinstActUserList = procinstActUserService.findByProcinstActivityIdActionType(procinstActivity.getId(), "0", "1");
                if (procinstActUserList.size() > 0) {

                    BusinessOut finalBusinessOut = businessOut;
                    new Thread(() -> {
                        for (ProcinstActUser procinstActUser : procinstActUserList) {
                            PersonInfo personInfo = personInfoService.get(Long.parseLong(procinstActUser.getUserId()));

                            //提交人
                            PersonInfo personInfo1 = personInfoService.get(personPopedom.getPersonId());
                            String accessToken = JwtUtil2.createToken(jwtSecret, personInfo.getId() + "", DateTime.now().plusHours(30 * 24).toDate());
                            WechatMessageUtil.sendEvenMessage(personInfo.getOpenId(), "有一条新的出差信息待审核", personInfo1.getName(), com.jpsoft.shinestar.modules.common.utils.StringUtils.getApprovalNo(), "前往处理", wxConfig.getPortalUrl() + "xsy/approval/infosp?id=" + finalBusinessOut.getId() + "&procinstActUserId=" + procinstActUser.getId() + "&formId=" + formId + "&token=" + accessToken, wxConfig.getAppId(), wxConfig.getAppSecret());
                        }
                    }).start();
                }
            }
        }
        return businessOut.getId();
    }

    @Override
    public void logic(BusinessOut businessOut) throws Exception {
        //更新人员工作状态
        updatePersonWorkStatus(businessOut);

        Date now = new Date();
        if (businessOut.getStartTime().before(now)) {
            PersonPopedom personPopedom = personPopedomService.get(businessOut.getPersonPopedomId());
            PersonInfo personInfo = personInfoService.get(personPopedom.getPersonId());

            UpdatePersonAttendanceDTO updatePersonAttendanceDTO = new UpdatePersonAttendanceDTO(
                    personInfo.getId(), businessOut.getStartTime(),businessOut.getEndTime());

            rabbitTemplate.convertAndSend("updatePersonAttendanceQueue", updatePersonAttendanceDTO);
        }
    }

    @Override
    public List<BusinessOut> listSearch(Map<String, Object> searchParams, List<Sort> sortList) {
        return businessOutDAO.search(searchParams,sortList);
    }

    @Override
    public List<BusinessOut> findByGreaterEndTime(Date date,String personPopedomId) {
        return businessOutDAO.findByGreaterEndTime(date,personPopedomId);
    }

    @Override
    public BigDecimal sumDaysByPersonIdAndTimeRange(Long personId, Date startDate, Date endDate){
        //查询时间段与出差交集部分
        List<BusinessOut> boList = businessOutDAO.findByPersonIdAndSEDate(personId,startDate,endDate);
        BigDecimal totalAttendanceNum = BigDecimal.ZERO;

        for(BusinessOut bo : boList){
//            if(bo.getEstimatedTime() != null) {
//                BigDecimal et = new BigDecimal(bo.getEstimatedTime());
//                totalAttendanceNum = totalAttendanceNum.add(et);
//            }
            //查询交集部分小时数
            Date maxStartDate = bo.getStartTime().compareTo(startDate)>0 ? bo.getStartTime() : startDate;
            Date minEndDate = bo.getEndTime().compareTo(endDate)<0 ? bo.getEndTime() : endDate;

            int hours = Hours.hoursBetween(new DateTime(maxStartDate),new DateTime(minEndDate)).getHours();
            BigDecimal days = new BigDecimal(hours).divide(new BigDecimal(24),1, RoundingMode.HALF_UP);

            totalAttendanceNum = totalAttendanceNum.add(days);
        }

        return totalAttendanceNum;
    }
}