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.vo.*;
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.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

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

/**
 * <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) {
        IPage<Flight> pages = flightService.page(new Page<>(dto.getPageNum(), dto.getPageSize()),
                new LambdaQueryWrapper<Flight>()
                        .orderByDesc(Flight::getCreateTime)
                        .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())
                        .eq(null == dto.getTissueUnitId(), Flight::getTissueUnitId, getUnitId())
                        .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.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())
                    .eq(null == dto.getTissueUnitId(), Flight::getTissueUnitId, getUnitId())
                    .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<FlightUnitTotalVO>> unitTotal(@Parameter(description = "班次名称") @RequestParam(required = false) String flightName,
                                          @Parameter(description = "年度") @RequestParam(required = false) String year) {


        List<FlightUnitTotalVO> unitTotalVOS = new ArrayList<FlightUnitTotalVO>();
        List<Flight> flights = flightService.list(new LambdaQueryWrapper<Flight>()
                .like(StringUtils.isNotBlank(flightName), Flight::getFlightName, flightName)
                .eq(StringUtils.isNotBlank(year), Flight::getYear, year)
                .eq(Flight::getCreateDept, getUnitId())
        );
        for (Flight flight : flights) {
            Date trainingTime = flight.getTrainingTime();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(trainingTime);
            calendar.add(Calendar.DATE,Integer.valueOf(flight.getEducationalSystem()));
            flight.setEndTime(calendar.getTime());
        }
        Map<String, List<Flight>> map = flights.stream().collect(Collectors.groupingBy(Flight::getMainUnitName));


        map.keySet().forEach(k -> {
            unitTotalVOS.add(
                    new FlightUnitTotalVO()
                    .setUnitName(k)
                    //实际班级数
                    .setActualNum(CollectionUtils.isNotEmpty(map.get(k)) ? map.get(k).size() : 0)
                    //待培训班级数
                    .setAwaitNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                            (int) map.get(k).stream().filter(l -> new Date().compareTo(l.getTrainingTime())< 0).count() : 0)
                    //正在培训班级数
                    .setProceedNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                            (int) map.get(k).stream().filter(
                                    l -> l.getTrainingTime().compareTo(new Date()) < 0 && l.getEndTime().compareTo(new Date())>0).count() : 0)
                    //已培训班级数
                    .setCompleteNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                            (int) map.get(k).stream().filter(
                                    l -> l.getEndTime().compareTo(new Date()) < 0).count() : 0));

        });
        return R.data(unitTotalVOS);
    }


    /**
     * 班次单位统计导出
     */
    @GetMapping("/unitTotal/export")
    @ApiOperationSupport(order = 3)
    @Log(title = "单位统计导出", businessType = BusinessType.EXPORT)
    @Operation(summary = "班次统计列表-单位统计导出", description = "传入ids")
    public void unitTotalExport(HttpServletResponse response, @Validated FlightPageDTO dto) {
        List<FlightUnitTotalVO> unitTotalVOS = new ArrayList<FlightUnitTotalVO>();
        List<Flight> flights = flightService.list(new LambdaQueryWrapper<Flight>()
                .like(StringUtils.isNotBlank(dto.getFlightName()), Flight::getFlightName, dto.getFlightName())
                .eq(StringUtils.isNotBlank(dto.getYear()), Flight::getYear, dto.getYear())
                .eq(Flight::getCreateDept, getUnitId())
        );
        for (Flight flight : flights) {
            Date trainingTime = flight.getTrainingTime();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(trainingTime);
            calendar.add(Calendar.DATE,Integer.valueOf(flight.getEducationalSystem()));
            flight.setEndTime(calendar.getTime());
        }
        Map<String, List<Flight>> map = flights.stream().collect(Collectors.groupingBy(Flight::getMainUnitName));

        map.keySet().forEach(k -> {
            unitTotalVOS.add(
                    new FlightUnitTotalVO()
                            .setUnitName(k)
                            //实际班级数
                            .setActualNum(CollectionUtils.isNotEmpty(map.get(k)) ? map.get(k).size() : 0)
                            //待培训班级数
                            .setAwaitNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                                    (int) map.get(k).stream().filter(l -> new Date().compareTo(l.getTrainingTime())< 0).count() : 0)
                            //正在培训班级数
                            .setProceedNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                                    (int) map.get(k).stream().filter(
                                            l -> l.getTrainingTime().compareTo(new Date()) < 0 && l.getEndTime().compareTo(new Date())>0).count() : 0)
                            //已培训班级数
                            .setCompleteNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                                    (int) map.get(k).stream().filter(
                                            l -> l.getEndTime().compareTo(new Date()) < 0).count() : 0));

        });

        ExcelUtil<FlightUnitTotalVO> excelUtil = new ExcelUtil<>(FlightUnitTotalVO.class);
        excelUtil.exportExcel(response, 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<FlightYearTotalVO>> yearTotal(@Parameter(description = "班次名称") @RequestParam(required = false) String flightName,
                                          @Parameter(description = "年度") @RequestParam(required = false) String year) {

        List<FlightYearTotalVO> yearTotalVOS = new ArrayList<FlightYearTotalVO>();
        List<Flight> flights = flightService.list(new LambdaQueryWrapper<Flight>()
                .like(StringUtils.isNotBlank(flightName), Flight::getFlightName, flightName)
                .eq(StringUtils.isNotBlank(year), Flight::getYear, year)
                .eq(Flight::getCreateDept, getUnitId())
        );

        for (Flight flight : flights) {
            Date trainingTime = flight.getTrainingTime();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(trainingTime);
            calendar.add(Calendar.DATE,Integer.valueOf(flight.getEducationalSystem()));
            flight.setEndTime(calendar.getTime());
        }

        Map<String, List<Flight>> map = flights.stream().collect(Collectors.groupingBy(Flight::getYear));
        map.keySet().forEach(k -> {
            yearTotalVOS.add(new FlightYearTotalVO()
                    .setYear(k)
                    //实际班级数
                    .setActualNum(CollectionUtils.isNotEmpty(map.get(k)) ? map.get(k).size() : 0)
                    //待培训班级数
                    .setAwaitNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                            (int) map.get(k).stream().filter(l -> new Date().compareTo(l.getTrainingTime())< 0).count() : 0)
                    //正在培训班级数
                    .setProceedNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                            (int) map.get(k).stream().filter(
                                    l -> l.getTrainingTime().compareTo(new Date()) < 0 && l.getEndTime().compareTo(new Date())>0).count() : 0)
                    //已培训班级数
                    .setCompleteNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                            (int) map.get(k).stream().filter(
                                    l -> l.getEndTime().compareTo(new Date()) < 0).count() : 0));

        });
        return R.data(yearTotalVOS);
    }

    /**
     * 班次单位统计导出
     */
    @GetMapping("/yearTotal/export")
    @ApiOperationSupport(order = 3)
    @Log(title = "年度统计导出", businessType = BusinessType.EXPORT)
    @Operation(summary = "班次统计列表-年度统计导出", description = "传入ids")
    public void yearTotalExport(HttpServletResponse response, @Validated FlightPageDTO dto) {
        List<FlightYearTotalVO> yearTotalVOS = new ArrayList<FlightYearTotalVO>();
        List<Flight> flights = flightService.list(new LambdaQueryWrapper<Flight>()
                .like(StringUtils.isNotBlank(dto.getFlightName()), Flight::getFlightName, dto.getFlightName())
                .eq(StringUtils.isNotBlank(dto.getYear()), Flight::getYear, dto.getYear())
                .eq(Flight::getCreateDept, getUnitId())
        );

        for (Flight flight : flights) {
            Date trainingTime = flight.getTrainingTime();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(trainingTime);
            calendar.add(Calendar.DATE,Integer.valueOf(flight.getEducationalSystem()));
            flight.setEndTime(calendar.getTime());
        }

        Map<String, List<Flight>> map = flights.stream().collect(Collectors.groupingBy(Flight::getYear));
        map.keySet().forEach(k -> {
            yearTotalVOS.add(new FlightYearTotalVO()
                    .setYear(k)
                    //实际班级数
                    .setActualNum(CollectionUtils.isNotEmpty(map.get(k)) ? map.get(k).size() : 0)
                    //待培训班级数
                    .setAwaitNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                            (int) map.get(k).stream().filter(l -> new Date().compareTo(l.getTrainingTime())< 0).count() : 0)
                    //正在培训班级数
                    .setProceedNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                            (int) map.get(k).stream().filter(
                                    l -> l.getTrainingTime().compareTo(new Date()) < 0 && l.getEndTime().compareTo(new Date())>0).count() : 0)
                    //已培训班级数
                    .setCompleteNum(CollectionUtils.isNotEmpty(map.get(k)) ?
                            (int) map.get(k).stream().filter(
                                    l -> l.getEndTime().compareTo(new Date()) < 0).count() : 0));
        });

        ExcelUtil<FlightYearTotalVO> excelUtil = new ExcelUtil<>(FlightYearTotalVO.class);
        excelUtil.exportExcel(response, yearTotalVOS, "班次年度统计数据");
    }


    /**
     * 专业（班次）树形
     */
    @GetMapping("/list/tree")
    @ApiOperationSupport(order = 9)
    @Operation(summary = "专业（班次）树形", description = "传入budget")
    public R<List<FlightTreeVO>> list() {
        List<SysDictData> data = dictDataService.list(new LambdaQueryWrapper<SysDictData>()
                .orderByAsc(SysDictData::getDictCode)
                .eq(SysDictData::getDictType, 1));
        List<Flight> list = flightService.list();
        if (CollectionUtils.isNotEmpty(list)) {
            Map<String, List<Flight>> listMap = list.stream().collect(Collectors.groupingBy(Flight::getMajorType));
            return R.data(data.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()));
        }
        return R.data(data.stream().map(d ->
                new FlightTreeVO()
                        .setId(Long.parseLong(d.getDictLabel()))
                        .setName(d.getDictValue())
                        .setList(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);
            }
        }
    }

}
