package com.zjty.tynotes.job.basic.service.impl;

import com.google.common.collect.Lists;
import com.zjty.tynotes.address.server.service.NoticeService;
import com.zjty.tynotes.job.basic.entity.database.ScoreCoefficient;
import com.zjty.tynotes.job.basic.entity.database.Work;
import com.zjty.tynotes.job.basic.entity.database.WorkTime;
import com.zjty.tynotes.job.basic.entity.response.WorkIsNotCommit;
import com.zjty.tynotes.job.basic.entity.response.WorkMpping;
import com.zjty.tynotes.job.basic.entity.response.WorkOverTime;
import com.zjty.tynotes.job.basic.repository.WorkRepository;
import com.zjty.tynotes.job.basic.service.ConversionService;
import com.zjty.tynotes.job.basic.service.ScoreCoefficientService;
import com.zjty.tynotes.job.basic.service.WorkService;
import com.zjty.tynotes.job.basic.service.WorkTimeService;
import com.zjty.tynotes.job.basic.utils.WorkingTime;
import com.zjty.tynotes.job.common.constant.WorkStatus;
import com.zjty.tynotes.job.common.exception.BadRequestException;
import com.zjty.tynotes.job.common.exception.NotFoundException;
import com.zjty.tynotes.pas.entity.User;
import com.zjty.tynotes.pas.entity.vo.HolidayRequest;
import com.zjty.tynotes.pas.entity.vo.JobLeads;
import com.zjty.tynotes.pas.service.ConfigService;
import com.zjty.tynotes.pas.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.CompletableFuture;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;

/**
 * <p>Description : note
 * <p>Date : 2019/4/23 11:32
 * <p>@author : C
 * 接口定义说明见↓
 *
 * @see WorkService
 */
@Slf4j
@Service
public class WorkServiceImpl implements WorkService {

    private final
    WorkRepository workRepository;

    @Autowired
    IUserService iUserService;

    @Autowired
    ConversionService conversionService;

    @Autowired
    ScoreCoefficientService scoreCoefficientService;

    @Autowired
    WorkTimeService workTimeService;

    @Autowired
    private NoticeService noticeService;

    @Autowired
    public WorkServiceImpl(WorkRepository workRepository) {
        this.workRepository = workRepository;
    }
    @Autowired
    ConfigService configService;

    @Override
    public String add(Work work) {
        //新增数据不可附带id.
        Boolean idMustNull = isNull(work.getId());
        if (idMustNull) {
            work.setCreateTime(new Date());
            work.setUpdateTime(new Date());
            JobLeads jobLeads=iUserService.findJobLeads(work.getExecutor());
            work.setMajordomos(jobLeads.getMajordomos());
            work.setAssistantManagers(jobLeads.getAssistantManagers());
            work.setGeneralManagers(jobLeads.getGeneralManagers());
            String saveId = workRepository.save(work).getId();
            log.info(String.format("[job]  新增了id为 %s 的数据.", saveId));

            CompletableFuture.runAsync(()->{
                if(work.getSuperiorId()==null){
                    List<String> otherIds = new ArrayList<>();
                    List<String> crewList = work.getCrewList();//获取组员id集合
                    @NotNull String publisher = work.getPublisher();
                    List<String> userIdList = noticeService.findUserIdList(publisher);//查找发布者下的人员id集合
                    if(crewList!=null){
                        crewList.forEach(s -> {
                            if(!userIdList.contains(s)){
                                otherIds.add(s);
                                System.out.println("需要请求人的id"+s);
                            }

                        });
                    }
                    //查找发布者的部门等级
                    String level = noticeService.findDepartLevel(publisher);
                    List<User> users = noticeService.findUser(level);//查找与发布者相同等级的人
                    if(users!=null){
                        Map<String,List<String>> map = noticeService.findLeadUser(users,otherIds,level);//查找所借人的id集合
                        if(map!=null){
                            Optional<Work> optional = workRepository.findById(saveId);
                            if(optional.isPresent()){
                                Work work1 = optional.get();
                                noticeService.submitNotice(work1.getPublisher(),map,work1.getId(),work1.getTitle());
                            }

                        }
                    }
                }
            });

            return saveId;
        } else {
            String msg = "[job] %s: 新增数据不可附带id.";
            log.error(msg);
            throw new BadRequestException(msg);
        }
    }

    private String selectGroupId(String id){
        Work work=workRepository.findById(id).get();
        String workId=work.getSuperiorId();
        if (workId==null || "".equals(workId)){
            return work.getExecutor();
        }
        return selectGroupId(workId);
    }
    @Override
    public String modify(Work work) {
        //更新数据必须指定id且指定id的数据存在.
        Boolean idMustExist = (nonNull(work.getId())) && (workRepository.existsById(work.getId()));
        if (idMustExist) {
            String modifyId = workRepository.save(work).getId();
            log.info(String.format("[job] 更新了id为 %s 的数据.", modifyId));
            return modifyId;
        } else {
            String msg = "[job] 更新数据必须指定id且指定id的数据存在.";
            log.error(msg);
            throw new BadRequestException(msg);
        }
    }

    @Override
    public List<Work> findAll() {
        return workRepository.findAll();
    }

    @Override
    public List<Work> findAll(List<String> ids) {
        return Lists.newArrayList(workRepository.findAllById(ids));
    }

    @Override
    public Boolean idExists(String workId) {
        return workRepository.existsById(workId);
    }

    @Override
    public Work findById(String workId) {
        Optional<Work> workOptional = workRepository.findById(workId);

        return workOptional.orElseThrow(() -> new BadRequestException(String.format("[job] id为 %s 的数据不存在.", workId)));
    }

    @Override
    public void delete(String workId) {
        if (workRepository.existsById(workId)) {
            workRepository.deleteById(workId);
        } else {
            throw new NotFoundException(String.format("[job] id为 %s 的工作不存在.", workId));
        }
    }

    @Override
    public void deleteAll() {
    }


    @Override
    public void alterTaskStatus(String taskId, String status, String userId) {
        Work ob = workRepository.findById(taskId).get();
        ob.setStatus(status);
        Date time=new Date();
        if (WorkStatus.ONGOING.equals(status)){
                ob.setAuditTime(time);
                workTimeService.saveWorkEndTime(ob,time);

        }else if (WorkStatus.AUDIT.equals(status)){
            ob.setSubmitTime(time);
            workTimeService.saveWorkStartTime(ob,time);

            Float expect= score(ob.getStateTime(),ob.getCompleteTime());
            Float practical=practical(taskId);
            log.info("预计完成时间："+expect+"--真实完成时间："+practical);
            if (expect<practical){
                float times=  practical-expect;
                ob.setWorkCoefficient(beyond(1,1.0f,times));
                //添加
            }else if (expect.equals(practical)){
                ob.setWorkCoefficient(1f);
            }else {
                float times=  expect-practical;
                ob.setWorkCoefficient(advance(1,1.0f,times));
            }

        }else if (WorkStatus.REVIEW.equals(status)) {
        //
            ob.setAuditTime(time);

        }else if (status.equals(WorkStatus.FINISHED)){
            pWorkload(taskId);
            ob.setEndTime(time);
        }

        workRepository.save(ob);
    }

    @Override
    public void alterTaskStatus1(String taskId, String status, String userId) {
        Work ob = workRepository.findById(taskId).get();
        ob.setStatus(status);
        workRepository.save(ob);
    }

    private Float practical(String workId){
        Float count=0.0f;
        List<WorkTime> workTimes=workTimeService.selectWorkTime(workId);
        for (WorkTime workTime:workTimes){
            Float s=score(workTime.getStartTime(),workTime.getEndTime());
            count=count+s;
        }
        return count;
    }

    private void pWorkload(String workId){
     ScoreCoefficient scoreCoefficient= scoreCoefficientService.findById(workId);
      int workLoad=  findBySuperoirIdCount(workId);
        DecimalFormat df=new  DecimalFormat("#.##");
        double coefficient= (Double.parseDouble(scoreCoefficient.getJustScore4())+Double.parseDouble(scoreCoefficient.getViceScore3()))/2/100;
        double getWorkLoad=workLoad*coefficient;
        scoreCoefficient.setEndWorkLoad(Double.valueOf(df.format(getWorkLoad)));
        scoreCoefficientService.modify(scoreCoefficient);
    }

private float beyond(float count,float coefficient,Float time){
        if (coefficient<0.5f){
            return 0.5f;
        }
        float si=time-4;

        if (si<4){
            return coefficient-0.025f*count;
        }else {
            coefficient=coefficient-0.025f*count;
        }
        count++;
        return beyond(count,coefficient,si);
}

    private float advance(float count1,float coefficient1,Float time){
        if (coefficient1>1.2f){
            return 1.2f;
        }
        float remainingTime=time-6;

        if (remainingTime<6){
            return coefficient1+0.025f*count1;
        }else {
            coefficient1=coefficient1 +0.025f*count1;
        }
        count1++;
        return advance(count1,coefficient1,remainingTime);
    }

private Float score(Date startTime,Date entTime){
   List<Date> dates= configService.findHolidays(new HolidayRequest(startTime,entTime));
    try {
       return WorkingTime.findOperHours(dates,startTime,entTime);
    } catch (ParseException e) {
        e.printStackTrace();
    }
return 0.0f;
}

    @Override
    public void deleteWork(String taskId, int personalWorkload, int workloadCount) {
        Work ob = workRepository.findById(taskId).get();
        ob.setPWorkload(personalWorkload);
        ob.setWorkloadCount(workloadCount);
        ob.setStatus(WorkStatus.DELETE);
        workRepository.save(ob);
    }

    @Override
    public void updateWorkCrew(String taskId, List<String> crews,Integer workload) {
        Work ob = workRepository.findById(taskId).get();
        ob.setCrewList(crews);
        ob.setWorkload(workload);
        workRepository.save(ob);
    }

    @Override
    public void updateWorkload(String taskId, int workload, float workCoefficient) {
        Work ob = workRepository.findById(taskId).get();
        ob.setWorkload(workload);
        ob.setWorkCoefficient(workCoefficient);
        workRepository.save(ob);
    }

    @Override
    public WorkIsNotCommit findBySuperoirId(String SuperoirId) {
        if (!workRepository.existsById(SuperoirId)){
            throw new NotFoundException(String.format("[job] id为 %s 的任务不存在.", SuperoirId));
        }
       List<Work> works= workRepository.findBySuperiorId(SuperoirId);
       List<String> list=new ArrayList<>();
       String isNotCommit="1";
       if (works!=null && works.size()!=0){
           for (Work work:works){
               if (!WorkStatus.FINISHED.equals(work.getStatus())){
                   isNotCommit="0";
                   list.add(work.getId());
               }
           }
           return new WorkIsNotCommit(isNotCommit,list);
       }else {
           return new WorkIsNotCommit(isNotCommit,list);
       }
    }

    @Override
    public int findBySuperoirIdCount(String SuperoirId) {
        if (!workRepository.existsById(SuperoirId)){
            throw new NotFoundException(String.format("[job] id为 %s 的任务不存在.", SuperoirId));
        }
        List<Work> works= workRepository.findBySuperiorId(SuperoirId);
        int count= workRepository.findById(SuperoirId).get().getWorkload();
        if (works!=null && works.size()!=0){
            for (Work work:works){
                if(work.getWorkloadCount()==1) {
                    count = count - work.getWorkload();
                }
            }
            return count;
        }else {
            return count;
        }

    }

    @Override
    public List<WorkMpping> selectUserIdsWork(String userId) {
       List<Work> works= workRepository.findAllByExecutorIn(iUserService.findUsers(userId));
        List<WorkMpping> workMppings=new ArrayList<>();
        for (Work work:works){
             if (work.getSuperiorId()==null || work.getSuperiorId().equals("")){
                 workMppings.add(new WorkMpping(work.getId(),work.getTitle(),work.getStatus(),iUserService.findUserById(work.getPublisher()).getUsername(),iUserService.findUserById(work.getExecutor()).getUsername(),workMppingList(work,works)));
             }else {

                 //如果上级id不为空 查询works中是否有这个任务的上级任务 如没有这个任务在这次查询中视为主任务显示。
                 boolean falg=true;
                 for (Work work1:works) {
                     if (work.getSuperiorId().equals(work1.getId())){
                         falg=false;
                     }
                 }

                 if (falg){
                     workMppings.add(new WorkMpping(work.getId(),work.getTitle(),work.getStatus(),iUserService.findUserById(work.getPublisher()).getUsername(),iUserService.findUserById(work.getExecutor()).getUsername(),workMppingList(work,works)));
                 }
             }
        }
        return  workMppings;
    }

    @Override
    public WorkMpping selectWorkMapperWorkId(String workId) {
       Work work= workRepository.findById(sumWorkId(workId)).get();

        return new WorkMpping(work.getId(),work.getTitle(),work.getStatus(),iUserService.findUserById(work.getPublisher()).getUsername(),iUserService.findUserById(work.getExecutor()).getUsername(),selectWorkMapper(work.getId()));
    }

    @Override
    public List<WorkOverTime> selectWorkToWorkOverTime(String userId) {

        List<WorkOverTime> workOverTimes=new ArrayList<>();
        workRepository.findByExecutorAndStatus(userId,WorkStatus.ONGOING).forEach(
                work -> {
                    List<User> users=new ArrayList<>();
                    for (String id:work.getCrewList()){
                        users.add(iUserService.findUserById(id));
                    }
                    workOverTimes.add(new WorkOverTime(work.getId(),work.getTitle(),users));
                }
        );
        return workOverTimes;
    }

    private List<WorkMpping>  selectWorkMapper(String workId){
        List<WorkMpping> workMppings=new ArrayList<>();
        List<Work> works=  workRepository.findBySuperiorId(workId);
        if (works.size()==0){
            return workMppings;
        }
        for (Work work:works){
            if (work.getSuperiorId()!=null || work.getSuperiorId().equals("")){
                workMppings.add(new WorkMpping(work.getId(),work.getTitle(),work.getStatus(),iUserService.findUserById(work.getPublisher()).getUsername(),iUserService.findUserById(work.getExecutor()).getUsername(),selectWorkMapper(work.getId())));
            }
        }
        return workMppings;
    }

    private String sumWorkId(String workId){
       Work work= workRepository.findById(workId).get();
       if (work.getSuperiorId()==null ||work.getSuperiorId().equals("")){
           return workId;
       }
       return sumWorkId(work.getSuperiorId());

    }

    private List<WorkMpping> workMppingList(Work work,List<Work> workList){
        List<WorkMpping> workMppings=new ArrayList<>();
       List<Work> works=new ArrayList<>();
       for (Work wo:workList){
           if (wo.getSuperiorId()!=null && wo.getSuperiorId().equals(work.getId())){
               works.add(wo);
           }
       }
       if ( works.size()==0){
           return workMppings;
       }
       for (Work work1:works){
            workMppings.add(new WorkMpping(work1.getId(),work1.getTitle(),work1.getStatus(),iUserService.findUserById(work1.getPublisher()).getUsername(),iUserService.findUserById(work1.getExecutor()).getUsername(),workMppingList(work1,workList)));
       }
       return workMppings;
    }
//    @Override
//    public List<Work> selectTimeWork() {
////        LocalDateTime minTime = LocalDateTime.now().with(LocalTime.MIN).atZone(ZoneOffset.ofHours(8)).ge;
//        workRepository.findByCompleteTimeGreaterThan(new Date());
//        return null;
//    }
}
