package com.ruoyi.project.service.impl;

import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.UserRolesType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.project.bo.MyMonthDays;
import com.ruoyi.project.bo.ProjectStaffRecordInput;
import com.ruoyi.project.bo.ProjectStaffRecordOut;
import com.ruoyi.project.domain.ProjectStaffRecord;
import com.ruoyi.project.domain.ProjectStaffRecordLog;
import com.ruoyi.project.mapper.ProjectStaffRecordLogMapper;
import com.ruoyi.project.mapper.ProjectStaffRecordMapper;
import com.ruoyi.project.mapper.ProjectTaskMapper;
import com.ruoyi.project.service.ProjectStaffRecordService;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.impl.SysConfigServiceImpl;
import com.ruoyi.weChat.service.WeChatService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.Validator;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

@Service
public class ProjectStaffRecordServiceImpl implements ProjectStaffRecordService {

    private static final Logger log = LoggerFactory.getLogger(ProjectStaffRecordServiceImpl.class);
    @Autowired
    private ProjectStaffRecordMapper projectStaffRecordMapper;
    @Autowired
    private ProjectStaffRecordLogMapper projectStaffRecordLogMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private ProjectTaskMapper projectTaskMapper;
    @Autowired
    protected Validator validator;
    @Autowired
    private WeChatService weChatService;
    @Autowired
    private ISysDeptService deptService;
    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysConfigServiceImpl configService;



    @Override
    public AjaxResult add(ProjectStaffRecord in) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        String username = user.getNickName();
        in.setName(username);
        if(in.getProcessStatus()>1)in.setProcessStatus(1);

        boolean flag=false;
        if (SecurityUtils.hashRoles(UserRolesType.INSPECTORS.getCode())){
            in.setProcessStatus(2);
            sysUserMapper.userAddDuration(in.getAid(),in.getDuration());
            projectTaskMapper.projectAddDuration(in.getPid(),in.getDuration());
        }else {
            flag=true;
        }
        addRecordLog(in);
        projectStaffRecordMapper.insertSelective(in);
        if (flag){
            addWechatAppSend(in, String.format("[%s]发起研发打卡,请及时审核!", username));
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult addCheckMaxDuration(ProjectStaffRecord in) {
        BigDecimal maxDuration= new BigDecimal(SecurityUtils.getLoginUser().getUser().getDept().getMaxDuration());
        String maxDurationProjectFlag = configService.selectConfigByKey("maxDurationProject");
        Boolean maxflag = Boolean.parseBoolean(maxDurationProjectFlag);
        Double myDuration;
        myDuration=getMyDuration(in,maxflag);
        BigDecimal mySum = new BigDecimal(myDuration).add(new BigDecimal(in.getDuration()));

        if (mySum.compareTo(maxDuration)==1){
            String errorStr=String.format("每天工时超出最大限制,最大额[%s],当前总额[%s]",maxDuration,mySum);
            log.debug(errorStr);
            return AjaxResult.error(errorStr);
        }

        return AjaxResult.success();
    }

    @Override
    public AjaxResult updateCheckMaxDuration(ProjectStaffRecord in) {
        BigDecimal maxDuration= new BigDecimal(SecurityUtils.getLoginUser().getUser().getDept().getMaxDuration());
        String maxDurationProjectFlag = configService.selectConfigByKey("maxDurationProject");
        AtomicReference<Double> aDouble = new AtomicReference<>(0d);
        String date=DateUtils.getDate();
        Boolean maxflag = Boolean.parseBoolean(maxDurationProjectFlag);
        List<ProjectStaffRecord> projectStaffRecords;
        if (maxflag){
             projectStaffRecords = projectStaffRecordMapper.selectByPidAndAid(in.getPid(),in.getAid());
        }else {
            projectStaffRecords = projectStaffRecordMapper.selectByPidAndAid(null,in.getAid());
        }

        projectStaffRecords.stream().forEach(e ->{
            String eDate= DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, e.getRecordTime());
            if (!e.getId().equals(in.getId())){
                if (date.equals(eDate)){
                    aDouble.updateAndGet(v -> v + e.getDuration());
                }
            }

        });
        aDouble.updateAndGet(v -> v + in.getDuration());
        BigDecimal mySum= new BigDecimal(aDouble.toString());
        if (mySum.compareTo(maxDuration)==1){
                String errorStr=String.format("每天工时超出最大限制,最大额[%s],当前总额[%s]",maxDuration,mySum);
                log.debug(errorStr);
                return AjaxResult.error(errorStr);
            }
            return AjaxResult.success();

    }

    @Override
    public AjaxResult myDurationMonth(Long id) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        BigDecimal maxDuration= new BigDecimal(loginUser.getUser().getDept().getMaxDuration());
        String  date=DateUtils.getDate();
        Long aid=loginUser.getUserId();
        List<MyMonthDays> myMonthDays = projectStaffRecordMapper.myDurationMonth(id, aid, DateUtils.firsDayOfMonth(), DateUtils.lastDayOfMonth() + " 23:59:59");
        supplementMyMonthDays(myMonthDays);
        for (MyMonthDays myMonthDay : myMonthDays) {
//            0 =未到时限 1=满工时,2=未打卡,3=未满工时
            if (compareTo(date,myMonthDay.getDates())){
                myMonthDay.setStatus(0);
            }else if (myMonthDay.getDuration().equals("0")) {
                myMonthDay.setStatus(2);
            }else if (new BigDecimal(myMonthDay.getDuration()).compareTo(maxDuration)<0){
                myMonthDay.setStatus(3);
            }else if (new BigDecimal(myMonthDay.getDuration()).compareTo(maxDuration)==0){
                myMonthDay.setStatus(1);
            }
        }
        return AjaxResult.success(myMonthDays);
    }

    @Override
    public AjaxResult recordDetails(Long id) {
        return AjaxResult.success(projectStaffRecordMapper.selectDetailsById(id));
    }

    /**
     *
     * @param date 当前时间
     * @param dates 获取时间
     * @return time>time2
     */
    private boolean compareTo(String date, String dates) {
        long time = DateUtils.parseDate(date).getTime();
        long time2 = DateUtils.parseDate(dates).getTime();
        if (time<time2){
            return true;
        }else {
            return false;
        }
    }

    private void supplementMyMonthDays(List<MyMonthDays> myMonthDays) {
        List<String> monthDays = getMonthDays();
        for (String monthDay : monthDays) {
            boolean flag= true;
            for (MyMonthDays myMonthDay : myMonthDays) {
                if (monthDay.equals(myMonthDay.getDates())){
                    flag=false;
                    break;
                }
            }
            if (flag){
                MyMonthDays mmd=new MyMonthDays();
                mmd.setDates(monthDay);
                mmd.setDuration("0");
                mmd.setStatus(0);
                myMonthDays.add(mmd);
            }
        }
    }

    private static List<String> getMonthDays() {
        String firsDayOfMonth = DateUtils.firsDayOfMonth();
        String lastDayOfMonth = DateUtils.lastDayOfMonth();
        List<String> dates=new ArrayList<>();

        String str=firsDayOfMonth.substring(0,firsDayOfMonth.lastIndexOf("-"));
        System.out.println(str);
        for (int i=1; i<32;i++){
            String res;
            if (i<10){
                 res=str+"-0"+i;
            }else {
                res=str+"-"+i;
            }
            dates.add(res);
            if (res.equals(lastDayOfMonth)){
                break;
            }
        }
        return dates;
    }



    private void addWechatAppSend(ProjectStaffRecord in, String remarks) {
        //获取当事人
        String openId=null;
        if (in.getProcessStatus()==1){
            SysUser sysUser = userMapper.selectSuperUserByUid(in.getAid());
            openId=sysUser.getOpenId();
            if (StringUtils.isBlank(openId)){
                log.debug(String.format("查询上级openId为空,%s",remarks));
            }
        }else if(in.getProcessStatus()==2||in.getProcessStatus()==3){
            SysUser sysUser = userMapper.selectUserById(in.getAid());
            openId=sysUser.getOpenId();
            if (StringUtils.isBlank(openId)){
                log.debug(String.format("查询发起人openId为空,%s",remarks));
            }
        }
        if (StringUtils.isNotBlank(openId)){
            weChatService.addNotice(openId, in.getId(),new Date(),remarks);
        }
    }

    private void addRecordLog(ProjectStaffRecord in) {
        ProjectStaffRecordLog log = new ProjectStaffRecordLog();
        log.setPsrId(in.getId());
        log.setProcessStatus(in.getProcessStatus());
        if (in.getProcessStatus()<2){
            log.setAid(in.getAid());
            log.setName(in.getName());
            log.setContent(getContent(in.getProcessStatus()));
        }else {
            log.setAid(SecurityUtils.getUserId());
            log.setName(SecurityUtils.getLoginUser().getUser().getNickName());
            log.setContent(getContent(in.getProcessStatus())+in.getContent());
        }
        projectStaffRecordLogMapper.insertSelective(log);
    }

    private String getContent(Integer processStatus) {
        switch (processStatus) {
            case 0: return "修改了内容！";
            case 1: return "发起了审核！";
            case 2: return "完成了审核！";
            case 3: return "驳回了审核！";
        }
        return "";
    }

    @Override
    public AjaxResult update(ProjectStaffRecord in) {
        ProjectStaffRecord projectStaffRecord = projectStaffRecordMapper.selectByPrimaryKey(in.getId());
        if (projectStaffRecord.getProcessStatus()!=0&&projectStaffRecord.getProcessStatus()!=3){
            AjaxResult.success("打卡只有草稿和驳回状态才可以修改!");
        }
        String username = SecurityUtils.getLoginUser().getUser().getNickName();
        in.setName(username);
        if(in.getProcessStatus()>1)in.setProcessStatus(1);
        projectStaffRecordMapper.updateByPrimaryKeySelective(in);
        if (in.getProcessStatus()==1){
            addWechatAppSend(in, String.format("[%s]发起研发打卡,及时是审核!", username));
        }
        addRecordLog(in);
        return AjaxResult.success();
    }

    @Override
    public AjaxResult examineRecord(ProjectStaffRecord in) {
        ProjectStaffRecord newP = new ProjectStaffRecord();
        newP.setId(in.getId());
        newP.setProcessStatus(in.getProcessStatus());
        String username=SecurityUtils.getLoginUser().getUser().getNickName();
        ProjectStaffRecord use = projectStaffRecordMapper.selectByPrimaryKey(in.getId());
        in.setAid(use.getAid());
        if (in.getProcessStatus()==2){
            if (use.getProcessStatus()!=1){
                AjaxResult.error("项目流程无需审核！");
            }
            sysUserMapper.userAddDuration(use.getAid(),use.getDuration());
            projectTaskMapper.projectAddDuration(use.getPid(),use.getDuration());
            newP.setExamineName(username);
            newP.setExamineId(SecurityUtils.getUserId());
            newP.setExamineTime(new Date());
        }
        projectStaffRecordMapper.updateByPrimaryKeySelective(newP);
        if (in.getProcessStatus()==2){
            addWechatAppSend(in, String.format("[%s]已审核[%s]您的研发打卡.", username,"同意"));
        }else if (in.getProcessStatus()==3){
            addWechatAppSend(in, String.format("[%s]已审核[%s]您的研发打卡.", username,"驳回"));
        }
        addRecordLog(in);
        return AjaxResult.success();
    }

    @Override
    public List<ProjectStaffRecordOut> listRecord(ProjectStaffRecordInput in) {
        if (in.getRoleType()==null)in.setRoleType(0);
        if (in.getRoleType()==0){
            in.setAid(SecurityUtils.getUserId());
        }else if (in.getRoleType()==1){
        //判定1=经理审核成员2=技术总监审核经理
            if (SecurityUtils.hashRoles(UserRolesType.INSPECTORS.getCode())){
                in.setRoleType(2);
            }
        }else if (in.getRoleType()==3){

        }
        Long companyId = deptService.selectCompanyByDeptId();
        if (companyId!=null)in.setCompanyId(companyId);
        return projectStaffRecordMapper.selectList(in);
    }

    @Override
    public String importProject(List<ProjectStaffRecordOut> list, boolean isUpdateSupport, String operName) {
        if (StringUtils.isNull(list) || list.size() == 0)
        {
            throw new ServiceException("导入用户数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        for (ProjectStaffRecordOut p : list)
        {
            try
            {
                // 验证是否存在
                ProjectStaffRecord projectStaffRecord = projectStaffRecordMapper.selectByPrimaryKey(p.getId());
                if (StringUtils.isNull(projectStaffRecord)){
                    BeanValidators.validateWithException(validator, projectStaffRecord);
                    projectStaffRecordMapper.insertSelective(p);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、项目： " + p.getName() + " 导入成功");
                }else if (isUpdateSupport){
                    BeanValidators.validateWithException(validator, p);
                    projectStaffRecordMapper.updateByPrimaryKeySelective(p);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、项目： " + p.getName() + " 更新成功");
                }
                else
                {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、项目： " + p.getName() + " 已存在");
                }
            }
            catch (Exception e)
            {
                failureNum++;
                String msg = "<br/>" + failureNum + "、项目: " + p.getName() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0)
        {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        }
        else
        {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public AjaxResult myDuration(Long id,String recordTime) {
        String maxDurationProjectFlag = configService.selectConfigByKey("maxDurationProject");
        Boolean flag = Boolean.parseBoolean(maxDurationProjectFlag);
        if (flag){
            if (id==null){
                return AjaxResult.error("项目不能为空");
            }
        }
        SysUser user = SecurityUtils.getLoginUser().getUser();
        SysDept dept = user.getDept();
        Double maxDuration=dept.getMaxDuration();
        Double myDuration=getMyDuration(id,user.getUserId(),recordTime);
        BigDecimal res = new BigDecimal(maxDuration).subtract(new BigDecimal(myDuration.toString()));
        return AjaxResult.success(res);
    }



    public Double getMyDuration(ProjectStaffRecord in ,boolean flag) {
        Long pid=in.getPid();
        Long aid=in.getAid();
        if (!flag)pid=null;
        String recordTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, in.getRecordTime());
        return getMyDuration(pid,aid,recordTime);
    }

    public Double getMyDuration(Long pid ,Long aid ,String recordTime) {
        Double myDuration = 0d;


        List<ProjectStaffRecord> projectStaffRecords = projectStaffRecordMapper.selectByPidAndAid(pid,aid);
        for (ProjectStaffRecord e : projectStaffRecords) {
            String eDate= DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, e.getRecordTime());
            if (recordTime.equals(eDate)){
                myDuration+=e.getDuration();
            }
        }
        return myDuration;
    }
}
