package com.xiaoniu.subsystem.business.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.xiaoniu.common.core.constant.Constants;
import com.xiaoniu.common.core.result.R;
import com.xiaoniu.common.core.utils.StringUtils;
import com.xiaoniu.common.core.vo.AnalysisLineVO;
import com.xiaoniu.common.core.vo.LabelAndValueNameVO;
import com.xiaoniu.common.log.annotation.Log;
import com.xiaoniu.common.log.enums.BusinessType;
import com.xiaoniu.subsystem.business.domain.Demand;
import com.xiaoniu.subsystem.business.domain.Project;
import com.xiaoniu.subsystem.business.domain.ProjectPersonnelInfo;
import com.xiaoniu.subsystem.business.domain.dto.ExpenseStatisticsDTO;
import com.xiaoniu.subsystem.business.domain.vo.ProfessionVO;
import com.xiaoniu.subsystem.business.domain.vo.TypeStatisticsVO;
import com.xiaoniu.subsystem.business.service.*;
import com.xiaoniu.subsystem.system.domain.SysDictData;
import com.xiaoniu.subsystem.system.domain.Unit;
import com.xiaoniu.subsystem.system.service.ISysDictDataService;
import com.xiaoniu.subsystem.system.service.IUnitService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.time.Year;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.xiaoniu.common.security.utils.SecurityUtils.getLoginUser;
import static com.xiaoniu.common.security.utils.SecurityUtils.getUnitId;

/**
 * 首页统计接口
 *
 * @packageName: com.xiaoniu.subsystem.business.controller
 * @className: HomeStatisticsController.java
 * @author: 孙松涛
 * @date: 2024-11-29 17:06
 * @version:
 */
@RestController
@AllArgsConstructor
@Tag(name = "首页统计接口", description = "首页统计接口")
@RequestMapping("/home/statistics")
public class HomeStatisticsController {


    private final IDemandService demandService;
    private IProjectService projectService;
    private IProjectPersonnelInfoService personnelInfoService;
    private IExpenseService expenseService;
    private IUnitService unitService;
    private ISysDictDataService dictDataService;
    private IProjectUnitService projectUnitService;


    /**
     * 培训班次统计信息
     */
    @GetMapping("/message")
    @ApiOperationSupport(order = 1)
    @Operation(summary = "首页统计-培训班次统计信息", description = "传入dto")
    public R<List<LabelAndValueNameVO>> message(ExpenseStatisticsDTO dto) {
        Set<String> roles = getLoginUser().getRoles();
        dto.setRoles(roles.toArray(new String[0])[0]);
        List<LabelAndValueNameVO> voList = new ArrayList<>();
        if (!StringUtils.equals("LJ", dto.getRoles()) && !StringUtils.equals("ZQLJ", dto.getRoles())) {
            voList.add(new LabelAndValueNameVO().setName("未培训").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("培训中").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("已培训").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("总计").setValue("0"));
            return R.data(voList);
        }
        LambdaQueryWrapper<Project> eq = new LambdaQueryWrapper<Project>()
                .eq(StringUtils.equals("ZQLJ", dto.getRoles()), Project::getCreateDept, getUnitId())
                .eq(Project::getParentId, 0)
                .ne(Project::getIsDistribution, 0)
                .eq(StringUtils.isBlank(dto.getYear()), Project::getYear, Year.now().getValue())
                .eq(StringUtils.isNotBlank(dto.getYear()), Project::getYear, dto.getYear());
        if (StringUtils.equals("LJ", dto.getRoles())) {
            List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                    .eq(Unit::getParentId, getUnitId()));
            List<Long> list = new ArrayList<>(units.stream().map(Unit::getUnitId).toList());
            list.add(getUnitId());
            eq.in(Project::getCreateDept, list);
        }
        List<Project> list = projectService.list(eq);
        if (CollectionUtils.isEmpty(list)) {
            voList.add(new LabelAndValueNameVO().setName("未培训").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("培训中").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("已培训").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("总计").setValue("0"));
            return R.data(voList);
        }
        voList.add(new LabelAndValueNameVO()
                .setName("未培训")
                .setValue(String.valueOf(list.stream().filter(i -> i.getActualTrainingTime().after(new Date())).count())));
        voList.add(new LabelAndValueNameVO()
                .setName("培训中")
                .setValue(String.valueOf(list.stream().filter(i -> i.getActualTrainingTime().before(new Date()) &&
                        i.getEndTime().after(new Date())).count())));
        voList.add(new LabelAndValueNameVO()
                .setName("已培训")
                .setValue(String.valueOf(list.stream().filter(i -> i.getEndTime().before(new Date())).count())));
        voList.add(new LabelAndValueNameVO()
                .setName("总计")
                .setValue(String.valueOf(list.stream().filter(i -> 4 != i.getIsDistribution()).count())));
        return R.data(voList);
    }


    /**
     * 统计信息
     */
    @GetMapping("/profession")
    @ApiOperationSupport(order = 2)
    @Operation(summary = "首页统计-专业统计", description = "传入dto")
    public R<ProfessionVO> profession(ExpenseStatisticsDTO dto) {
        ProfessionVO vo = new ProfessionVO();
        vo.setLabels(new ArrayList<>());
        List<Long> longs = unitService.juniorUnit(getUnitId());
        List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
                .in(!CollectionUtils.isEmpty(longs), Project::getCreateDept, longs)
                .eq(StringUtils.isBlank(dto.getYear()), Project::getYear, Year.now().getValue())
                .eq(StringUtils.isNotBlank(dto.getYear()), Project::getYear, dto.getYear()));
        SysDictData data = new SysDictData();
        data.setDictType("1");
        List<SysDictData> list1 = dictDataService.selectDictDataList(data);
        if (CollectionUtils.isEmpty(list)) {
            list1.forEach(l -> vo.getLabels().add(new LabelAndValueNameVO().setName(l.getDictValue()).setValue("0")));
            return R.data(vo);
        }
        long counts = 0L;
        for (SysDictData l : list1) {
            List<Long> collect = list.stream().filter(p -> l.getDictLabel().equals(p.getMajorType()))
                    .map(Project::getProjectId).collect(Collectors.toList());
            long count = 0L;
            if (CollectionUtils.isNotEmpty(collect)) {
                count = personnelInfoService.count(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                        .eq(ProjectPersonnelInfo::getIsReport, 1)
                        .in(ProjectPersonnelInfo::getProjectId, collect));
            }
            vo.getLabels().add(new LabelAndValueNameVO().setName(l.getDictValue())
                    .setValue(String.valueOf(count)));
            counts = counts + count;
        }
        vo.setTotal((int) counts);
        return R.data(vo);
    }

    /**
     * 统计信息
     */
    @GetMapping("/type")
    @ApiOperationSupport(order = 3)
    @Operation(summary = "首页统计-类型统计", description = "传入dto")
    public R<TypeStatisticsVO> type(ExpenseStatisticsDTO dto) {
        TypeStatisticsVO vo = new TypeStatisticsVO();
        vo.setLabels(new ArrayList<>());
        List<Long> longs = unitService.juniorUnit(getUnitId());
        List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
                .in(!CollectionUtils.isEmpty(longs), Project::getCreateDept, longs)
                .eq(StringUtils.isBlank(dto.getYear()), Project::getYear, Year.now().getValue())
                .eq(StringUtils.isNotBlank(dto.getYear()), Project::getYear, dto.getYear()));
        SysDictData data = new SysDictData();
        data.setDictType("2");
        List<SysDictData> list1 = dictDataService.selectDictDataList(data);
        if (CollectionUtils.isEmpty(list)) {
            list1.forEach(l -> vo.getLabels().add(new LabelAndValueNameVO().setName(l.getDictValue()).setValue("0")));
            return R.data(vo);
        }
        for (SysDictData l : list1) {
            List<Long> collect = list.stream().filter(p -> p.getTrainingType().contains(l.getDictLabel()))
                    .map(Project::getProjectId).collect(Collectors.toList());
            long count = 0L;
            if (CollectionUtils.isNotEmpty(collect)) {
                count = personnelInfoService.count(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                        .eq(ProjectPersonnelInfo::getIsReport, 1)
                        .in(ProjectPersonnelInfo::getProjectId, collect));
            }
            vo.getLabels().add(new LabelAndValueNameVO().setName(l.getDictValue())
                    .setValue(String.valueOf(count)));
        }
        long count = personnelInfoService.count(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                .eq(ProjectPersonnelInfo::getIsReport, 1)
                .in(ProjectPersonnelInfo::getProjectId,
                        list.stream().map(Project::getProjectId).collect(Collectors.toList())));
        vo.setTotal(String.valueOf(count));
        return R.data(vo);
    }

    // /**
    //  * 首页统计-参训人员
    //  */
    // @GetMapping("/distribution")
    // @ApiOperationSupport(order = 4)
    // @Log(title = "首页统计-参训人员", businessType = BusinessType.OTHER)
    // @Operation(summary = "首页统计-参训人员", description = "传入dto")
    // public R<AnalysisLineVO> distribution(ExpenseStatisticsDTO dto) {
    //     AnalysisLineVO analysisLineVO = new AnalysisLineVO();
    //     List<AnalysisLineVO.DataList> dataList = new ArrayList<>();
    //     AnalysisLineVO.DataList list1 = new AnalysisLineVO.DataList();
    //     list1.setName("计划");
    //     list1.setType("line");
    //     list1.setYAxisData(new ArrayList<>());
    //     AnalysisLineVO.DataList list2 = new AnalysisLineVO.DataList();
    //     list2.setName("实际");
    //     list2.setType("line");
    //     list2.setYAxisData(new ArrayList<>());
    //     List<String> xAxisData = new ArrayList<>();
    //     Unit unit = unitService.getOne(new LambdaQueryWrapper<Unit>()
    //             .eq(Unit::getUnitId, getUnitId()));
    //     xAxisData.add(unit.getUnitName());
    //     Set<String> roles = getLoginUser().getRoles();
    //     dto.setRoles(roles.toArray(new String[0])[0]);
    //     if (!StringUtils.equals("BD", dto.getRoles())) {
    //         list1.getYAxisData().add("0");
    //         list2.getYAxisData().add("0");
    //     } else {
    //         List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
    //                 .eq(Project::getCreateDept, unit.getUnitId())
    //                 .eq(StringUtils.isBlank(dto.getYear()), Project::getYear, Year.now().getValue())
    //                 .eq(StringUtils.isNotBlank(dto.getYear()), Project::getYear, dto.getYear()));
    //         if (CollectionUtils.isEmpty(list)) {
    //             list1.getYAxisData().add("0");
    //             list2.getYAxisData().add("0");
    //         } else {
    //             list1.getYAxisData().add(list.stream().map(l ->
    //                             BigDecimal.valueOf(Double.parseDouble(StringUtils.isEmpty(l.getTrainingPost()) ?
    //                                     "0" : l.getTrainingPost())))
    //                     .reduce(BigDecimal.ZERO, BigDecimal::add).stripTrailingZeros().toPlainString());
    //             List<Long> ids = new ArrayList<>(list.stream().map(Project::getProjectId).toList());
    //             List<ProjectPersonnelInfo> list3 = personnelInfoService.list(new LambdaQueryWrapper<ProjectPersonnelInfo>()
    //                     .eq(ProjectPersonnelInfo::getIsReport, 1)
    //                     .in(ProjectPersonnelInfo::getProjectId, ids));
    //             list2.getYAxisData().add(String.valueOf(list3.size()));
    //         }
    //     }
    //     dataList.add(list1);
    //     dataList.add(list2);
    //     analysisLineVO.setXAxisData(xAxisData);
    //     analysisLineVO.setDataList(dataList);
    //     return R.data(analysisLineVO);
    // }
    /**
     * 费用统计-人员统计
     */
    @GetMapping("/distribution")
    @ApiOperationSupport(order = 4)
    @Log(title = "首页统计-学员分布", businessType = BusinessType.OTHER)
    @Operation(summary = "首页统计-学员分布", description = "传入dto")
    public R<AnalysisLineVO> distribution(ExpenseStatisticsDTO dto) {
        AnalysisLineVO analysisLineVO = new AnalysisLineVO();
        List<AnalysisLineVO.DataList> dataList = new ArrayList<>();
        AnalysisLineVO.DataList list1 = new AnalysisLineVO.DataList();
        list1.setName("计划");
        list1.setType("line");
        list1.setYAxisData(new ArrayList<>());
        AnalysisLineVO.DataList list2 = new AnalysisLineVO.DataList();
        list2.setName("实际");
        list2.setType("line");
        list2.setYAxisData(new ArrayList<>());
        List<String> xAxisData = new ArrayList<>();
        List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                .eq(Unit::getParentId, getUnitId()));
        for (Unit unit : units) {
            xAxisData.add(unit.getUnitName());
            List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
                    .eq(Project::getCreateDept, unit.getUnitId())
                    .eq(StringUtils.isBlank(dto.getYear()), Project::getYear, Year.now().getValue())
                    .eq(StringUtils.isNotBlank(dto.getYear()), Project::getYear, dto.getYear()));
            if (CollectionUtils.isEmpty(list)) {
                list1.getYAxisData().add("0");
                list2.getYAxisData().add("0");
            } else {
                list1.getYAxisData().add(list.stream().map(l ->
                                BigDecimal.valueOf(Double.parseDouble(StringUtils.isEmpty(l.getShouldAttendance()) ?
                                        "0" : l.getShouldAttendance())))
                        .reduce(BigDecimal.ZERO, BigDecimal::add).stripTrailingZeros().toPlainString());
                List<Long> ids = new ArrayList<>(list.stream().map(Project::getProjectId).toList());
                List<Project> all = getAll(ids);
                ids.addAll(all.stream().map(Project::getProjectId).toList());
                List<ProjectPersonnelInfo> list3 = personnelInfoService.list(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                        .in(ProjectPersonnelInfo::getProjectId, ids));
                list2.getYAxisData().add(String.valueOf(list3.size()));
            }
        }
        dataList.add(list1);
        dataList.add(list2);
        analysisLineVO.setXAxisData(xAxisData);
        analysisLineVO.setDataList(dataList);
        return R.data(analysisLineVO);
    }

    /**
     * 统计信息
     */
    @GetMapping("/demand/statistics")
    @ApiOperationSupport(order = 5)
    @Operation(summary = "首页统计-需求统计", description = "传入dto")
    public R<List<LabelAndValueNameVO>> demandStatistics(ExpenseStatisticsDTO dto) {
        Set<String> roles = getLoginUser().getRoles();
        dto.setRoles(roles.toArray(new String[0])[0]);
        List<LabelAndValueNameVO> voList = new ArrayList<>();
        if (!StringUtils.equals("LJ", dto.getRoles()) && !StringUtils.equals("ZQLJ", dto.getRoles())) {
            voList.add(new LabelAndValueNameVO().setName("已上报").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("待上报").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("总计").setValue("0"));
            return R.data(voList);
        }
        LambdaQueryWrapper<Demand> eq = new LambdaQueryWrapper<Demand>()
                .eq(StringUtils.equals("ZQLJ", dto.getRoles()), Demand::getCreateDept, getUnitId())
                .eq(Demand::getParentId, 0)
                .ne(Demand::getIsIssue, 0)
                .eq(StringUtils.isBlank(dto.getYear()), Demand::getYear, Year.now().getValue())
                .eq(StringUtils.isNotBlank(dto.getYear()), Demand::getYear, dto.getYear());
        if (StringUtils.equals("LJ", dto.getRoles())) {
            List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                    .eq(Unit::getParentId, getUnitId()));
            List<Long> list = new ArrayList<>(units.stream().map(Unit::getUnitId).toList());
            list.add(getUnitId());
            eq.in(Demand::getCreateDept, list);
        }
        List<Demand> list = demandService.list(eq);
        if (CollectionUtils.isEmpty(list)) {
            voList.add(new LabelAndValueNameVO().setName("已上报").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("待上报").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("总计").setValue("0"));
            return R.data(voList);
        }
        voList.add(new LabelAndValueNameVO()
                .setName("已上报")
                .setValue(String.valueOf(list.stream().filter(l ->
                        StringUtils.equals("1", l.getIsReport())).count())));
        voList.add(new LabelAndValueNameVO()
                .setName("待上报")
                .setValue(String.valueOf(list.stream().filter(l ->
                        StringUtils.equals("0", l.getIsReport())).count())));
        voList.add(new LabelAndValueNameVO()
                .setName("总计")
                .setValue(String.valueOf(list.stream().filter(l ->
                        !StringUtils.equals("3", l.getIsIssue())).count())));
        return R.data(voList);
    }

    /**
     * 统计信息
     */
    @GetMapping("/project/statistics")
    @ApiOperationSupport(order = 6)
    @Operation(summary = "首页统计-计划统计", description = "传入dto")
    public R<List<LabelAndValueNameVO>> projectStatistics(ExpenseStatisticsDTO dto) {
        Set<String> roles = getLoginUser().getRoles();
        dto.setRoles(roles.toArray(new String[0])[0]);
        List<LabelAndValueNameVO> voList = new ArrayList<>();
        if (!StringUtils.equals("LJ", dto.getRoles())
                && !StringUtils.equals("ZQLJ", dto.getRoles())
                && !StringUtils.equals("JTJ", dto.getRoles())) {
            voList.add(new LabelAndValueNameVO().setName("已上报").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("待上报").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("总计").setValue("0"));
            return R.data(voList);
        }
        LambdaQueryWrapper<Project> eq = new LambdaQueryWrapper<Project>()
                .ne(Project::getIsDistribution, 0)
                .eq(StringUtils.isBlank(dto.getYear()), Project::getYear, Year.now().getValue())
                .eq(StringUtils.isNotBlank(dto.getYear()), Project::getYear, dto.getYear());
        if (StringUtils.equals("LJ", dto.getRoles())) {
            List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                    .eq(Unit::getParentId, getUnitId()));
            List<Long> list = new ArrayList<>(units.stream().map(Unit::getUnitId).toList());
            list.add(getUnitId());
            eq.in(Project::getCreateDept, list).eq(Project::getParentId, 0);
        }
        if (StringUtils.equals("ZQLJ", dto.getRoles())) {
            eq.eq(Project::getCreateDept, getUnitId()).eq(Project::getParentId, 0);
        }
        if (StringUtils.equals("JTJ", dto.getRoles())) {
            eq.eq(Project::getCreateDept, getUnitId());
        }
        List<Project> list = projectService.list(eq);
        if (CollectionUtils.isEmpty(list)) {
            voList.add(new LabelAndValueNameVO().setName("已上报").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("待上报").setValue("0"));
            voList.add(new LabelAndValueNameVO().setName("总计").setValue("0"));
            return R.data(voList);
        }
        long count = list.stream().filter(l -> 1 != l.getIsDistribution()).count();
        int i = 0;
        List<Project> list1 = list.stream().filter(l -> 1 == l.getIsDistribution()).toList();
        for (Project project : list1) {
            List<Project> projectList = new ArrayList<>();
            List<Project> projects = projectService.list(
                    new LambdaQueryWrapper<Project>().eq(Project::getParentId, project.getProjectId()));
            if (CollectionUtils.isNotEmpty(projects)) {
                projectList.addAll(projects);
                setList(projects,projectList);
            }
            List<ProjectPersonnelInfo> list3 = personnelInfoService.list(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                    .eq(ProjectPersonnelInfo::getIsReport, 1)
                    .in(ProjectPersonnelInfo::getProjectId, projectList.stream().map(Project::getProjectId).toList()));
            if (CollectionUtils.isEmpty(list3)) {
                i = i + 1;
            } else {
                if (list3.size() < Integer.parseInt(project.getTrainingPost())) {
                    i = i + 1;
                } else {
                    count = count + 1;
                }
            }
        }
        voList.add(new LabelAndValueNameVO()
                .setName("已上报")
                .setValue(String.valueOf(count)));
        voList.add(new LabelAndValueNameVO()
                .setName("待上报")
                .setValue(String.valueOf(i)));
        voList.add(new LabelAndValueNameVO()
                .setName("总计")
                .setValue(String.valueOf(list.stream().filter(l ->
                        4 != l.getIsDistribution()).count())));
        return R.data(voList);
    }

    private void setList(List<Project> projects,List<Project> projectList) {
        List<Project> projects1 = projectService.list(new LambdaQueryWrapper<Project>()
                .in(Project::getParentId, projects.stream().map(Project::getProjectId).toList()));
        if (CollectionUtils.isNotEmpty(projects1)){
            projectList.addAll(projects1);
            setList(projects1,projectList);
        }
    }

    public List<Project> getAll(List<Long> ids) {
        List<Project> list = new ArrayList<>();
        List<Project> projects = projectService.list(new LambdaQueryWrapper<Project>()
                .in(Project::getParentId, ids).eq(Project::getIsDeleted, Constants.ZERO));
        if (CollectionUtils.isEmpty(projects)) {
            return list;
        }
        list.addAll(projects);
        list.addAll(getAll(projects.stream().map(Project::getProjectId).distinct().toList()));
        return list;
    }
}
