package com.usky.iot.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.usky.common.core.bean.ApiResult;
import com.usky.common.core.exception.BusinessException;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.iot.domain.PmProject;
import com.usky.iot.domain.PmWorkContent;
import com.usky.iot.domain.PmWorkReport;
import com.usky.iot.mapper.PmWorkContentMapper;
import com.usky.iot.mapper.PmWorkReportMapper;
import com.usky.iot.service.PmProjectService;
import com.usky.iot.service.PmWorkContentService;
import com.usky.iot.service.PmWorkReportService;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.iot.service.vo.PmProjectWorkTimeVo;
import com.usky.system.RemoteMceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;


/**
 * <p>
 * 工作报告表 服务实现类
 * </p>
 *
 * @author fu
 * @since 2024-05-20
 */
@Service
public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMapper, PmWorkReport> implements PmWorkReportService {

    @Autowired
    private PmWorkContentMapper pmWorkContentMapper;

    @Autowired
    private PmWorkReportMapper pmWorkReportMapper;

    @Autowired
    private PmProjectService pmProjectService;

    @Autowired
    private PmWorkContentService pmWorkContentService;

    @Autowired
    private RemoteMceService remoteMceService;

    /**
     * 获取时间内工作报告
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param reportId  报告id
     * @return
     */
    @Override
    public List<Map<String, List<PmWorkReport>>> weekWork(String startDate, String endDate, Integer reportId) {
        List<Map<String, List<PmWorkReport>>> returnList = new ArrayList<>();
        List<PmWorkReport> report = new ArrayList<>();
        Map<String, List<PmWorkReport>> weekData = new HashMap<>();
        Map<String, List<PmWorkReport>> newData = new HashMap<>();
        LocalDate startDate1 = null;
        LocalDate endDate1 = null;
        if (startDate == null && endDate == null) {
            startDate1 = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
            endDate1 = LocalDate.now().with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        } else {
            startDate1 = LocalDate.parse(startDate);
            endDate1 = LocalDate.parse(endDate);
        }
        List<LocalDate> dates = new ArrayList<>();
        LocalDate tempDate = startDate1;
        while (!tempDate.isAfter(endDate1)) {
            dates.add(tempDate);
            tempDate = tempDate.plusDays(1);
        }
        //固定返回七条数据，没有内容也要设置时间给前端渲染
        LambdaQueryWrapper<PmWorkReport> queryWrapperR = Wrappers.lambdaQuery();
        queryWrapperR.select(PmWorkReport::getId, PmWorkReport::getReportDate, PmWorkReport::getSubmitDate, PmWorkReport::getUpdateTime, PmWorkReport::getTomorrowPlan, PmWorkReport::getCoordinateWork, PmWorkReport::getCcTo)
                .eq(PmWorkReport::getSubmitterId, SecurityUtils.getUserId())
                .between(PmWorkReport::getReportDate, startDate1, endDate1)
                .orderByAsc(PmWorkReport::getReportDate)
                .apply(reportId != 0, "id = " + reportId);
        List<PmWorkReport> reports = baseMapper.selectList(queryWrapperR);
        if (reports.isEmpty()) {
            List<PmWorkReport> reports1 = new ArrayList<>();
            for (int f = 0; f < dates.size(); f++) {
                List<PmWorkContent> content = new ArrayList<>();
                PmWorkReport report1 = new PmWorkReport();
                report1.setReportDate(dates.get(f));
                report1.setWorkContents(content);
                reports1.add(report1);
            }
            weekData.put("weekData", reports1);
            newData.put("newData", report);
            returnList.add(0, newData);
            returnList.add(1, weekData);
            return returnList;
        }
        List<Integer> ids = new ArrayList<>();
        for (PmWorkReport pwr : reports) {
            ids.add(pwr.getId());
        }
        LambdaQueryWrapper<PmWorkContent> queryWrapperC = Wrappers.lambdaQuery();
        queryWrapperC.select(PmWorkContent::getId, PmWorkContent::getWorkContent, PmWorkContent::getWorkTime, PmWorkContent::getProjectId,
                PmWorkContent::getProjectName, PmWorkContent::getReportId, PmWorkContent::getCreateTime, PmWorkContent::getUpdateTime)
                .in(PmWorkContent::getReportId, ids)
                .orderByDesc(PmWorkContent::getWorkTime);
        List<PmWorkContent> contents = pmWorkContentMapper.selectList(queryWrapperC);
        int a, b;
        for (int i = 0; i < reports.size(); i++) {
            a = reports.get(i).getId();
            List<PmWorkContent> contentList = new ArrayList<>();
            for (int j = 0; j < contents.size(); j++) {
                b = contents.get(j).getReportId();
                if (b == a) {
                    contentList.add(contents.get(j));
                }
            }
            reports.get(i).setWorkContents(contentList);
        }
        if (reports.size() == 7 || reportId != 0) {
            weekData.put("weekData", reports);
            LambdaQueryWrapper<PmWorkReport> wrapper1 = Wrappers.lambdaQuery();
            wrapper1.eq(PmWorkReport::getSubmitterId, SecurityUtils.getUserId())
                    .orderByDesc(PmWorkReport::getReportDate)
                    .last("LIMIT 1");
            report = this.list(wrapper1);
            Integer rId = report.get(0).getId();
            LambdaQueryWrapper<PmWorkContent> wrapperC = Wrappers.lambdaQuery();
            wrapperC.eq(PmWorkContent::getProjectId, rId);
            List<PmWorkContent> pmWorkContents = pmWorkContentMapper.selectList(wrapperC);
            report.get(0).setWorkContents(pmWorkContents);
            newData.put("newData", report);
            returnList.add(0, newData);
            returnList.add(1, weekData);
            return returnList;
        }
        List<PmWorkReport> reportList = new ArrayList<>();
        for (int d = 0; d < dates.size(); d++) {
            boolean matchFound = false;
            for (int c = 0; c < reports.size(); c++) {
                if (dates.get(d).isEqual(reports.get(c).getReportDate())) {
                    reportList.add(reports.get(c));
                    matchFound = true;
                    break;
                }
            }
            if (!matchFound) {
                PmWorkReport newReport = new PmWorkReport();
                List<PmWorkContent> newContent = new ArrayList<>();
                newReport.setReportDate(dates.get(d));
                newReport.setWorkContents(newContent);
                reportList.add(newReport);
            }
        }
        //返回最新的一条数据给前端填充
        LambdaQueryWrapper<PmWorkReport> wrapper2 = Wrappers.lambdaQuery();
        wrapper2.eq(PmWorkReport::getSubmitterId, SecurityUtils.getUserId())
                .orderByDesc(PmWorkReport::getSubmitDate)
                .last("LIMIT 1");
        List<PmWorkReport> report2 = baseMapper.selectList(wrapper2);
        report = report2;
        Integer pId = report.get(0).getId();
        List<PmWorkContent> pmWorkContentList = new ArrayList<>();
        LambdaQueryWrapper<PmWorkContent> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(PmWorkContent::getReportId, pId);
        List<PmWorkContent> contents1 = pmWorkContentMapper.selectList(wrapper);
        for (PmWorkContent pmWorkContent : contents1) {
            Integer pId2 = pmWorkContent.getReportId();
            if (pId2 == pId) {
                pmWorkContentList.add(pmWorkContent);
            }
        }
        report.get(0).setWorkContents(pmWorkContentList);
        weekData.put("weekData", reportList);
        newData.put("newData", report);
        returnList.add(0, newData);
        returnList.add(1, weekData);
        return returnList;
    }

    /**
     * 新增、编辑工作报告
     */
    @Override
    public void addReport(PmWorkReport pmWorkReport) {
        BigDecimal totalWorkTime = BigDecimal.ZERO; //计算总工时
        int size = pmWorkReport.getWorkContents().size();
        for (int p = 0; p < size; p++) {
            for (int q = p + 1; q < size; q++) {
                if (pmWorkReport.getWorkContents().get(p).getProjectId() == pmWorkReport.getWorkContents().get(q).getProjectId()) {
                    throw new BusinessException("存在重复项目，请检查！");
                }
            }
        }
        for (PmWorkContent a : pmWorkReport.getWorkContents()) {
            totalWorkTime = totalWorkTime.add(a.getWorkTime());
        }
        //判断总工时是否超过24h
        BigDecimal noeDay = BigDecimal.valueOf(24);
        int compareResult = totalWorkTime.compareTo(noeDay);
        if (compareResult >= 0) {
            throw new BusinessException("一天24小时都不够你用，请检查当日总工时！");
        } else if (totalWorkTime == null || totalWorkTime.equals(BigDecimal.ZERO) || totalWorkTime.compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException("工时不能为空！");
        }
        //判断是否携带reportId，不写带则为新增报告，携带则为编辑（更新）项目
        if (pmWorkReport.getId() == null) {
            PmWorkReport newReport = new PmWorkReport();
            newReport.setReportDate(pmWorkReport.getReportDate());
            newReport.setSubmitterId(SecurityUtils.getUserId());
            newReport.setSubmitDate(LocalDateTime.now());
            newReport.setCcTo(pmWorkReport.getCcTo());
            newReport.setCoordinateWork(pmWorkReport.getCoordinateWork());
            newReport.setTomorrowPlan(pmWorkReport.getTomorrowPlan());
            newReport.setCreateBy(SecurityUtils.getUsername());
            newReport.setCreateTime(LocalDateTime.now());
            newReport.setDeptId(SecurityUtils.getLoginUser().getSysUser().getDeptId());
            newReport.setTenantId(SecurityUtils.getTenantId());
            newReport.setTotalHours(totalWorkTime);
            pmWorkReportMapper.insert(newReport);
            Integer id = newReport.getId();
            //获取报告中所有项目id
            List<Integer> projectIds = new ArrayList<>();
            for (PmWorkContent b1 : pmWorkReport.getWorkContents()) {
                projectIds.add(b1.getProjectId());
            }
            //查出所有项目id对应项目名
            List<PmProject> project = pmProjectService.projectName(projectIds);
            //将项目名重新赋值
            for (PmWorkContent b : pmWorkReport.getWorkContents()) {
                for (int c = 0; c < project.size(); c++) {
                    if (b.getProjectId() == project.get(c).getId()) {
                        b.setProjectName(project.get(c).getProjectName());
                    }
                }
                PmWorkContent newContent = new PmWorkContent();
                newContent.setReportId(newReport.getId());
                newContent.setProjectId(b.getProjectId());
                projectIds.add(b.getReportId());
                newContent.setProjectName(b.getProjectName());
                newContent.setSubmitterId(SecurityUtils.getUserId());
                newContent.setWorkContent(b.getWorkContent());
                newContent.setWorkTime(b.getWorkTime());
                newContent.setCreateBy(SecurityUtils.getUsername());
                newContent.setCreateTime(LocalDateTime.now());
                newContent.setDeptId(SecurityUtils.getLoginUser().getSysUser().getDeptId());
                newContent.setTenantId(SecurityUtils.getTenantId());
                pmWorkContentMapper.insert(newContent);
                //推送消息中心
                String nickName = SecurityUtils.getLoginUser().getSysUser().getNickName();
                String infoContent = nickName + "的工作报告";
//                List<Long> ids = Arrays.stream(newReport.getCcTo().split(","))
//                        .map(Long::parseLong)
//                        .collect(Collectors.toList());
                JsonObject jsonObject = new JsonObject();
                jsonObject.addProperty("infoTitle", "工作报告");
                jsonObject.addProperty("infoContent", infoContent);
                jsonObject.addProperty("infoType", 5);
                jsonObject.addProperty("id", id);
                jsonObject.addProperty("userIds", newReport.getCcTo());
                remoteMceService.addMce(jsonObject.toString());
                System.out.println(jsonObject);
            }
        } else {
            PmWorkReport rp = new PmWorkReport();
            rp.setId(pmWorkReport.getId());
            rp.setReportDate(pmWorkReport.getReportDate());
            rp.setSubmitterId(pmWorkReport.getSubmitterId());
            rp.setSubmitDate(pmWorkReport.getSubmitDate());
            rp.setCcTo(pmWorkReport.getCcTo());
            rp.setCoordinateWork(pmWorkReport.getCoordinateWork());
            rp.setTomorrowPlan(pmWorkReport.getTomorrowPlan());
            rp.setCreateBy(pmWorkReport.getCreateBy());
            rp.setCreateTime(pmWorkReport.getCreateTime());
            rp.setUpdateBy(SecurityUtils.getUsername());
            rp.setUpdateTime(LocalDateTime.now());
            rp.setDeptId(pmWorkReport.getDeptId());
            rp.setTenantId(pmWorkReport.getTenantId());
            rp.setUpdateBy(SecurityUtils.getUsername());
            rp.setUpdateTime(LocalDateTime.now());
            rp.setTotalHours(totalWorkTime);
            pmWorkReportMapper.updateById(rp);

            LambdaQueryWrapper<PmWorkContent> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.select(PmWorkContent::getReportId, PmWorkContent::getSubmitterId, PmWorkContent::getCreateBy, PmWorkContent::getCreateTime, PmWorkContent::getDeptId, PmWorkContent::getTenantId)
                    .eq(PmWorkContent::getReportId, pmWorkReport.getId())
                    .last("LIMIT 1");
            PmWorkContent f = pmWorkContentMapper.selectOne(queryWrapper);
            pmWorkContentService.deleteContent(pmWorkReport.getId());
            List<PmWorkContent> contents = pmWorkReport.getWorkContents();
            for (PmWorkContent e : contents) {
                e.setReportId(f.getReportId());
                e.setUpdateBy(SecurityUtils.getUsername());
                e.setUpdateTime(LocalDateTime.now());
                e.setSubmitterId(f.getSubmitterId());
                e.setCreateTime(f.getCreateTime());
                e.setCreateBy(f.getCreateBy());
                e.setDeptId(f.getDeptId());
                e.setTenantId(f.getTenantId());
                pmWorkContentMapper.insert(e);
            }
        }
    }

    @Override
    public List<Map<String, Object>> countTime() {
        int scale = 2;
        RoundingMode roundingMode = RoundingMode.HALF_UP;
        List<Map<String, Object>> returnList = new ArrayList<>();
        Map<String, Object> weekTotalMap = new HashMap<>();
        Map<String, Object> monthTotalMap = new HashMap<>();
        Map<String, Object> weekMap = new HashMap<>();
        Map<String, Object> monthMap = new HashMap<>();
        List<PmProjectWorkTimeVo> returnListW = new ArrayList<>();
        List<PmProjectWorkTimeVo> returnListM = new ArrayList<>();
        LocalDate today = LocalDate.now();
        LocalDate startOfWeek = today.with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY));
        LocalDate endOfWeek = today.with(TemporalAdjusters.nextOrSame(java.time.DayOfWeek.SUNDAY));
        LocalDateTime startOfWeekDateTime = startOfWeek.atStartOfDay();
        LocalDateTime endOfWeekDateTime = endOfWeek.atTime(23, 59, 59);
        LocalDate startOfMonth = today.withDayOfMonth(1);
        LocalDate endOfMonth = today.withDayOfMonth(today.lengthOfMonth());
        LocalDateTime startOfMonthDateTime = startOfMonth.atStartOfDay();
        LocalDateTime endOfMonthDateTime = endOfMonth.atTime(23, 59, 59);

        BigDecimal weekTotal = BigDecimal.ZERO;
        List<PmProjectWorkTimeVo> week = pmWorkContentMapper.workTimeCount(startOfWeekDateTime, endOfWeekDateTime, SecurityUtils.getUserId());
        if (week.isEmpty()) {
            weekTotalMap.put("WeekWorkTimeTotal", 0);
            weekMap.put("WeeklyData", week);
        }
        for (int i = 0; i < week.size(); i++) {
            weekTotal = weekTotal.add(week.get(i).getWorkTime());
        }
        BigDecimal totalPercentageW = BigDecimal.ZERO;
        for (int a = 0; a < week.size(); a++) {
            PmProjectWorkTimeVo workTimeVo = new PmProjectWorkTimeVo();
            workTimeVo.setProjectName(week.get(a).getProjectName());
            workTimeVo.setWorkTime(week.get(a).getWorkTime());
            if (a != week.size() - 1) {
                BigDecimal percentage = week.get(a).getWorkTime().divide(weekTotal, scale, roundingMode);
                workTimeVo.setPercentage(percentage);
                totalPercentageW = totalPercentageW.add(percentage);
            } else {
                BigDecimal lastPercentage = BigDecimal.ONE.subtract(totalPercentageW);
                workTimeVo.setPercentage(lastPercentage);
            }
            workTimeVo.setPercentage(week.get(a).getWorkTime().divide(weekTotal, scale, roundingMode));
            returnListW.add(workTimeVo);
        }

        BigDecimal monthTotal = BigDecimal.ZERO;
        List<PmProjectWorkTimeVo> month = pmWorkContentMapper.workTimeCount(startOfMonthDateTime, endOfMonthDateTime, SecurityUtils.getUserId());
        if (month.isEmpty()) {
            weekTotalMap.put("MonthWorkTimeTotal", 0);
            weekMap.put("MonthlyData", month);
        }
        for (int i = 0; i < month.size(); i++) {
            monthTotal = monthTotal.add(month.get(i).getWorkTime());
        }
        BigDecimal totalPercentageM = BigDecimal.ZERO;
        for (int b = 0; b < month.size(); b++) {
            PmProjectWorkTimeVo workTimeVo = new PmProjectWorkTimeVo();
            workTimeVo.setProjectName(month.get(b).getProjectName());
            workTimeVo.setWorkTime(month.get(b).getWorkTime());
            if (b != month.size() - 1) {
                BigDecimal percentage = month.get(b).getWorkTime().divide(monthTotal, scale, roundingMode);
                workTimeVo.setPercentage(percentage);
                totalPercentageM = totalPercentageM.add(percentage);
            } else {
                BigDecimal lastPercentage = BigDecimal.ONE.subtract(totalPercentageM);
                workTimeVo.setPercentage(lastPercentage);
            }

            returnListM.add(workTimeVo);
        }

        weekTotalMap.put("WeekWorkTimeTotal", weekTotal);
        monthTotalMap.put("MonthWorkTimeTotal", monthTotal);
        weekMap.put("WeeklyData", returnListW);
        monthMap.put("MonthlyData", returnListM);
        returnList.add(weekTotalMap);
        returnList.add(monthTotalMap);
        returnList.add(weekMap);
        returnList.add(monthMap);
        return returnList;
    }
}
