package com.xiaoniu.subsystem.business.controller;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.xiaoniu.common.core.result.R;
import com.xiaoniu.common.core.utils.BeanUtil;
import com.xiaoniu.common.core.utils.poi.ExcelUtil;
import com.xiaoniu.common.log.annotation.Log;
import com.xiaoniu.common.log.enums.BusinessType;
import com.xiaoniu.subsystem.business.domain.Flight;
import com.xiaoniu.subsystem.business.domain.Project;
import com.xiaoniu.subsystem.business.domain.dto.FlightDTO;
import com.xiaoniu.subsystem.business.domain.dto.FlightPageDTO;
import com.xiaoniu.subsystem.business.domain.dto.FlightTreeDTO;
import com.xiaoniu.subsystem.business.domain.vo.FlightTreeVO;
import com.xiaoniu.subsystem.business.domain.vo.FlightVO;
import com.xiaoniu.subsystem.business.domain.vo.UnitTotalVO;
import com.xiaoniu.subsystem.business.domain.vo.YearTotalVO;
import com.xiaoniu.subsystem.business.service.IFlightService;
import com.xiaoniu.subsystem.business.service.IProjectService;
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.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import static com.xiaoniu.common.security.utils.SecurityUtils.*;

/**
 * <p>
 * 专业（班次）管理表 前端控制器
 * </p>
 *
 * @author haoxuyang
 * @since 2024-11-29 03:35:08
 */
@RestController
@AllArgsConstructor
@Tag(name = "专业（班次）管理表", description = "专业（班次）管理表接口")
@RequestMapping("/flight")
public class FlightController {

    private IFlightService flightService;
    private IProjectService projectService;
    private IUnitService unitService;
    private ISysDictDataService dictDataService;

    /**
     * 详情
     */
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @Operation(summary = "详情", description = "传入budget")
    public R<FlightVO> detail(@Parameter(description = "主键", required = true) @RequestParam Long flightId) {
        Flight detail = flightService.getById(flightId);
        return R.data(BeanUtil.copy(detail, FlightVO.class));
    }

    /**
     * 分页 专业（班次）管理
     */
    @GetMapping("/page")
    @ApiOperationSupport(order = 2)
    @Operation(summary = "分页", description = "传入budget")
    public R<IPage<FlightVO>> page(@Validated FlightPageDTO dto) {
        // List<Project> list = projectService.list(
        //         new LambdaQueryWrapper<Project>().eq(Project::getCreateDept, getUnitId()));
        // if (CollectionUtils.isEmpty(list)){
        //     return R.data(new Page<>(dto.getPageNum(), dto.getPageSize()));
        // }
        // List<Long> list1 = list.stream().map(Project::getFlightId).collect(Collectors.toList());
        // List<Project> list2 = projectService.list(new LambdaQueryWrapper<Project>()
        //         .in(Project::getParentId, list.stream().map(Project::getProjectId).collect(Collectors.toList())));
        // if (CollectionUtils.isNotEmpty(list2)) {
        //     list1.addAll(list2.stream().map(Project::getProjectId).toList());
        // }
        IPage<Flight> pages = flightService.page(new Page<>(dto.getPageNum(), dto.getPageSize()),
                new LambdaQueryWrapper<Flight>()
                        .orderByDesc(Flight::getCreateTime)
                        // .in(CollectionUtils.isNotEmpty(list1),Flight::getFlightId,list1)
                        .eq(null != dto.getStatus(), Flight::getStatus, dto.getStatus())
                        .like(StringUtils.isNotBlank(dto.getFlightName()), Flight::getFlightName, dto.getFlightName())
                        .eq(null != dto.getTissueUnitId(), Flight::getTissueUnitId, dto.getTissueUnitId())
                        .like(StringUtils.isNotBlank(dto.getTissueUnitName()), Flight::getTissueUnitName, dto.getTissueUnitName())
                        .eq(StringUtils.isNotBlank(dto.getYear()), Flight::getYear, dto.getYear()));
        return R.data(BeanUtil.copy(pages, FlightVO.class));
    }

    /**
     * 导出
     */
    @GetMapping("/export")
    @ApiOperationSupport(order = 3)
    @Log(title = "导出", businessType = BusinessType.EXPORT)
    @Operation(summary = "导出", description = "传入ids")
    public void export(HttpServletResponse response, @Validated FlightPageDTO dto) {
        List<Flight> list = new ArrayList<>();
        if (StringUtils.isNotBlank(dto.getIds())) {
            list.addAll(flightService.list(new LambdaQueryWrapper<Flight>()
                    .orderByDesc(Flight::getCreateTime)
                    .in(StringUtils.isNotBlank(dto.getIds()), Flight::getFlightId,
                            Arrays.stream(dto.getIds().split(",")).toList())));
        } else {
            // List<Project> list1 = projectService.list(
            //         new LambdaQueryWrapper<Project>().eq(Project::getCreateDept, getUnitId()));
            // if (CollectionUtils.isNotEmpty(list1)){
            //     List<Long> list2 = list1.stream().map(Project::getFlightId).collect(Collectors.toList());
            //     List<Project> list3 = projectService.list(new LambdaQueryWrapper<Project>()
            //             .in(Project::getParentId, list1.stream().map(Project::getProjectId).collect(Collectors.toList())));
            //     if (CollectionUtils.isNotEmpty(list3)) {
            //         list2.addAll(list3.stream().map(Project::getProjectId).toList());
            //     }
            //
            // }
            list.addAll(flightService.list(new LambdaQueryWrapper<Flight>()
                    .orderByDesc(Flight::getCreateTime)
                    // .in(CollectionUtils.isNotEmpty(list1),Flight::getFlightId,list1)
                    .eq(null != dto.getStatus(), Flight::getStatus, dto.getStatus())
                    .like(StringUtils.isNotBlank(dto.getFlightName()), Flight::getFlightName, dto.getFlightName())
                    .eq(null != dto.getTissueUnitId(), Flight::getTissueUnitId, dto.getTissueUnitId())
                    .like(StringUtils.isNotBlank(dto.getTissueUnitName()), Flight::getTissueUnitName, dto.getTissueUnitName())
                    .eq(StringUtils.isNotBlank(dto.getYear()), Flight::getYear, dto.getYear())));
        }
        ExcelUtil<Flight> excelUtil = new ExcelUtil<>(Flight.class);
        excelUtil.exportExcel(response, list, "专业（班次）数据");

    }

    /**
     * 新增 专业（班次）管理
     */
    @PostMapping("/save")
    @ApiOperationSupport(order = 4)
    @Operation(summary = "新增", description = "传入budget")
    public R save(@Valid @RequestBody FlightDTO dto) {
        return R.status(flightService.save(
                dto.setYear(String.valueOf(LocalDate.now().getYear()))
                        .setCreateDept(getUnitId()).setCreateUser(getUserId()).setCreateTime(new Date())));
    }

    /**
     * 修改 专业（班次）管理
     */
    @PostMapping("/update")
    @ApiOperationSupport(order = 5)
    @Operation(summary = "修改", description = "传入budget")
    public R update(@Valid @RequestBody FlightDTO dto) {
        return R.status(flightService.updateById(
                dto.setUpdateUser(getUserId()).setUpdateTime(new Date())));
    }


    /**
     * 班次统计列表-单位统计
     */
    @GetMapping("/unit/total")
    @ApiOperationSupport(order = 6)
    @Operation(summary = "班次统计列表-单位统计")
    public R<List<UnitTotalVO>> unitTotal(@Parameter(description = "班次名称") @RequestParam(required = false) String flightName,
                                          @Parameter(description = "年度") @RequestParam(required = false) String year) {
        List<UnitTotalVO> unitTotalVOS = new ArrayList<UnitTotalVO>();
        if (StringUtils.equals("admin", getUsername()) || 0 == getUnitId()) {
            return R.data(unitTotalVOS);
        }
        List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
                .like(StringUtils.isNotBlank(flightName), Project::getFlightName, flightName)
                .eq(StringUtils.isNotBlank(year), Project::getYear, year)
                .eq(Project::getCreateDept, getUnitId()));
        Unit unit = unitService.getById(getUnitId());
        List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                .eq(Unit::getParentId, unit.getUnitId()));
        List<Project> list1 = new ArrayList<Project>();
        List<UnitTotalVO> unitTotalVOS1 = new ArrayList<UnitTotalVO>();
        if (CollectionUtils.isNotEmpty(units)) {
            for (Unit u : units) {
                List<Project> projects = projectService.list(new LambdaQueryWrapper<Project>()
                        .like(StringUtils.isNotBlank(flightName), Project::getFlightName, flightName)
                        .eq(StringUtils.isNotBlank(year), Project::getYear, year)
                        .eq(Project::getCreateDept, u.getUnitId()));
                List<Project> projects1 = new ArrayList<Project>();
                List<Unit> uns = unitService.list(new LambdaQueryWrapper<Unit>()
                        .eq(Unit::getParentId, u.getUnitId()));
                if (CollectionUtils.isNotEmpty(units)) {
                    for (Unit u1 : uns) {
                        getUnitProjectVO(u1, flightName, year, projects1);
                    }
                }
                if (CollectionUtils.isNotEmpty(projects1)) {
                    projects.addAll(projects1.stream().filter(p -> 0 == p.getParentId()).toList());
                }
                unitTotalVOS1.add(new UnitTotalVO()
                        .setUnitName(u.getUnitName())
                        .setProjectNnum(CollectionUtils.isNotEmpty(projects) ? projects.size() : 0)
                        .setActualNum(CollectionUtils.isNotEmpty(projects) ?
                                (int) projects.stream().filter(l ->
                                        l.getTrainingTime().compareTo(new Date()) < 0).count() : 0)
                        .setAwaitNum(CollectionUtils.isNotEmpty(projects) ?
                                (int) projects.stream().filter(l ->
                                        new Date().compareTo(l.getTrainingTime()) < 0).count() : 0)
                        .setProceedNum(CollectionUtils.isNotEmpty(projects) ?
                                (int) projects.stream().filter(l -> l.getTrainingTime().compareTo(new Date()) < 0
                                        && new Date().compareTo(l.getEndTime()) < 0).count() : 0)
                        .setCompleteNum(CollectionUtils.isNotEmpty(projects) ?
                                (int) projects.stream().filter(l ->
                                        l.getEndTime().compareTo(new Date()) < 0).count() : 0));
                list1.addAll(projects);
            }
        }
        if (CollectionUtils.isNotEmpty(list1)) {
            list.addAll(list1.stream().filter(p -> 0 == p.getParentId()).toList());
        }
        unitTotalVOS.add(new UnitTotalVO()
                .setUnitName(unit.getUnitName())
                .setProjectNnum(CollectionUtils.isNotEmpty(list) ? list.size() : 0)
                .setActualNum(CollectionUtils.isNotEmpty(list) ?
                        (int) list.stream().filter(l ->
                                l.getTrainingTime().compareTo(new Date()) < 0).count() : 0)
                .setAwaitNum(CollectionUtils.isNotEmpty(list) ?
                        (int) list.stream().filter(l ->
                                new Date().compareTo(l.getTrainingTime()) < 0).count() : 0)
                .setProceedNum(CollectionUtils.isNotEmpty(list) ?
                        (int) list.stream().filter(l -> l.getTrainingTime().compareTo(new Date()) < 0
                                && new Date().compareTo(l.getEndTime()) < 0).count() : 0)
                .setCompleteNum(CollectionUtils.isNotEmpty(list) ?
                        (int) list.stream().filter(l ->
                                l.getEndTime().compareTo(new Date()) < 0).count() : 0));
        unitTotalVOS.addAll(unitTotalVOS1);
        return R.data(unitTotalVOS);
    }

    /**
     * 删除 专业（班次）管理
     */
    @PostMapping("/remove")
    @ApiOperationSupport(order = 7)
    @Operation(summary = "删除", description = "传入ids")
    public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String flightIds) {
        return R.status(flightService.removeByIds(Arrays.stream(flightIds.split(",")).toList()));
    }

    /**
     * 班次统计列表-年度统计
     */
    @GetMapping("/year/total")
    @ApiOperationSupport(order = 8)
    @Operation(summary = "班次统计列表-年度统计")
    public R<List<YearTotalVO>> yearTotal(@Parameter(description = "班次名称") @RequestParam(required = false) String flightName,
                                          @Parameter(description = "年度") @RequestParam(required = false) String year) {
        List<YearTotalVO> yearTotalVOS = new ArrayList<YearTotalVO>();
        if (StringUtils.equals("admin", getUsername()) || 0 == getUnitId()) {
            return R.data(yearTotalVOS);
        }
        List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
                .orderByDesc(Project::getYear)
                .like(StringUtils.isNotBlank(flightName), Project::getFlightName, flightName)
                .eq(StringUtils.isNotBlank(year), Project::getYear, year)
                .eq(Project::getCreateDept, getUnitId()));
        if (CollectionUtils.isEmpty(list)) {
            return R.data(yearTotalVOS);
        }
        Unit unit = unitService.getById(getUnitId());
        List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                .eq(Unit::getParentId, unit.getUnitId()));
        List<Project> list1 = new ArrayList<Project>();
        if (CollectionUtils.isNotEmpty(units)) {
            for (Unit u : units) {
                List<Project> projects = projectService.list(new LambdaQueryWrapper<Project>()
                        .like(StringUtils.isNotBlank(flightName), Project::getFlightName, flightName)
                        .eq(StringUtils.isNotBlank(year), Project::getYear, year)
                        .eq(Project::getCreateDept, u.getUnitId()));
                List<Project> projects1 = new ArrayList<Project>();
                List<Unit> uns = unitService.list(new LambdaQueryWrapper<Unit>()
                        .eq(Unit::getParentId, u.getUnitId()));
                if (CollectionUtils.isNotEmpty(units)) {
                    for (Unit u1 : uns) {
                        getUnitProjectVO(u1, flightName, year, projects1);
                    }
                }
                if (CollectionUtils.isNotEmpty(projects1)) {
                    projects.addAll(projects1.stream().filter(p -> 0 == p.getParentId()).toList());
                }
                list1.addAll(projects);
            }
        }
        if (CollectionUtils.isNotEmpty(list1)) {
            list.addAll(list1.stream().filter(p -> 0 == p.getParentId()).toList());
        }
        Map<String, List<Project>> listMap = list.stream().collect(Collectors.groupingBy(Project::getYear));
        listMap.keySet().forEach(k -> {
            yearTotalVOS.add(new YearTotalVO()
                    .setYear(k)
                    .setProjectNnum(CollectionUtils.isNotEmpty(listMap.get(k)) ? listMap.get(k).size() : 0)
                    .setActualNum(CollectionUtils.isNotEmpty(listMap.get(k)) ?
                            (int) listMap.get(k).stream().filter(l ->
                                    l.getTrainingTime().compareTo(new Date()) < 0).count() : 0)
                    .setAwaitNum(CollectionUtils.isNotEmpty(listMap.get(k)) ?
                            (int) listMap.get(k).stream().filter(l ->
                                    new Date().compareTo(l.getTrainingTime()) < 0).count() : 0)
                    .setProceedNum(CollectionUtils.isNotEmpty(listMap.get(k)) ?
                            (int) listMap.get(k).stream().filter(
                                    l -> l.getTrainingTime().compareTo(new Date()) < 0
                                    && new Date().compareTo(l.getEndTime()) < 0).count() : 0)
                    .setCompleteNum(CollectionUtils.isNotEmpty(listMap.get(k)) ?
                            (int) listMap.get(k).stream().filter(l ->
                                    l.getEndTime().compareTo(new Date()) < 0).count() : 0));
        });
        return R.data(yearTotalVOS);
    }


    /**
     * 专业（班次）树形
     */
    @PostMapping("/list/tree")
    @ApiOperationSupport(order = 9)
    @Operation(summary = "专业（班次）树形", description = "传入budget")
    public R<List<FlightTreeVO>> list(@Valid @RequestBody FlightTreeDTO dto) {
        List<Flight> list = flightService.list(new LambdaQueryWrapper<Flight>().in(Flight::getFlightId,
                dto.getIds()));
        if (CollectionUtils.isEmpty(list)) {
            return R.data(Collections.emptyList());
        }
        Map<String, List<Flight>> listMap = list.stream().collect(Collectors.groupingBy(Flight::getMajorType));
        List<SysDictData> data = dictDataService.list(new LambdaQueryWrapper<SysDictData>()
                .orderByAsc(SysDictData::getDictCode)
                .eq(SysDictData::getDictType, 1));
        List<SysDictData> sysDictData = new ArrayList<>();
        for (SysDictData datum : data) {
            if (CollectionUtils.isNotEmpty(listMap.get(datum.getDictLabel()))){
                sysDictData.add(datum);
            }
        }
        return R.data(sysDictData.stream().map(d ->
                new FlightTreeVO()
                        .setId(Long.parseLong(d.getDictLabel()))
                        .setName(d.getDictValue())
                        .setList(CollectionUtils.isNotEmpty(listMap.get(d.getDictLabel())) ?
                                listMap.get(d.getDictLabel()).stream().map(l -> new FlightTreeVO()
                                        .setId(l.getFlightId())
                                        .setName(l.getFlightName())).toList() : Collections.emptyList())
        ).collect(Collectors.toList()));
    }


    private void getUnitProjectVO(Unit unit, String flightName, String year, List<Project> projects) {
        List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
                .like(StringUtils.isNotBlank(flightName), Project::getFlightName, flightName)
                .eq(StringUtils.isNotBlank(year), Project::getYear, year)
                .eq(Project::getCreateDept, unit.getUnitId()));
        projects.addAll(list);
        List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                .eq(Unit::getParentId, unit.getUnitId()));
        if (CollectionUtils.isNotEmpty(units)) {
            for (Unit u : units) {
                getUnitProjectVO(u, flightName, year, projects);
            }
        }
    }

}
