package com.ximai.mes.cal.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ximai.common.annotation.Log;
import com.ximai.common.constant.UserConstants;
import com.ximai.common.core.controller.BaseController;
import com.ximai.common.core.domain.AjaxResult;
import com.ximai.common.core.page.TableDataInfo;
import com.ximai.common.enums.BusinessType;
import com.ximai.common.utils.MessageUtils;
import com.ximai.common.utils.SecurityUtils;
import com.ximai.common.utils.data.DateUtils;
import com.ximai.common.utils.data.ExceptionUtil;
import com.ximai.common.utils.excel.ExcelWriter;
import com.ximai.mes.cal.domain.CalPlan;
import com.ximai.mes.cal.domain.CalShift;
import com.ximai.mes.cal.dto.CalPlanExcelExport;
import com.ximai.mes.cal.mapper.CalPlanMapper;
import com.ximai.mes.cal.service.ICalPlanService;
import com.ximai.mes.cal.service.ICalPlanTeamService;
import com.ximai.mes.cal.service.ICalShiftService;
import io.swagger.annotations.ApiOperation;
import org.aspectj.bridge.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.ximai.common.utils.data.DateUtils.formatShiftDate;

/**
 * 排班计划Controller
 *
 * @date 2022-06-06
 */
@RestController
@RequestMapping("/mes/cal/calplan")
public class CalPlanController extends BaseController {
    @Autowired
    private ICalPlanService calPlanService;

    @Resource
    private CalPlanMapper calPlanMapper;
    @Autowired
    private ICalShiftService calShiftService;

    @Autowired
    private ICalPlanTeamService calPlanTeamService;

    /**
     * 查询排班计划列表
     */
    @PreAuthorize("@ss.hasPermi('mes:cal:calplan:list')")
    @GetMapping("/list")
    public TableDataInfo list(CalPlan calPlan) {
        startPage();
        List<CalPlan> list = calPlanService.selectCalPlanList(calPlan);
        return getDataTable(list);
    }

    /**
     * 获取排班计划详细信息
     */
    @PreAuthorize("@ss.hasPermi('mes:cal:calplan:query')")
    @GetMapping(value = "/{planId}")
    public AjaxResult getInfo(@PathVariable("planId") Long planId) {
        return AjaxResult.success(calPlanService.selectCalPlanByPlanId(planId));
    }

    /**
     * 新增排班计划
     */
    @PreAuthorize("@ss.hasPermi('mes:cal:calplan:add')")
    @Log(title = "排班计划新增", businessType = BusinessType.INSERT)
    @Transactional
    @PostMapping
    @ApiOperation("排班计划新增")
    public AjaxResult add(@RequestBody CalPlan calPlan) {
        checkPlan(calPlan);


        List<CalPlan> calPlans = calPlanMapper.selectListByQw(new QueryWrapper<CalPlan>().eq("plan_code", calPlan.getPlanCode()));
        ExceptionUtil.checkTrueThrowException(CollectionUtil.isNotEmpty(calPlans), MessageUtils.message("cal.error.error1"));


        // 插入方案
        calPlanService.insertCalPlan(calPlan);
        calPlanService.updateRelationship(calPlan);
        calPlanService.insertCalWorkunits(calPlan);
        return AjaxResult.success();
    }


    /**
     * 修改排班
     */
    @ApiOperation("排班计划修改完成")
    @PreAuthorize("@ss.hasPermi('mes:cal:calplan:edit')")
    @Log(title = "排班计划修改", businessType = BusinessType.UPDATE)
    @Transactional
    @PutMapping
    public AjaxResult edit(@RequestBody CalPlan calPlan) {
        checkPlan(calPlan);

        calPlanService.updateCalPlan(calPlan);
        calPlanService.updateRelationship(calPlan);
        calPlanService.insertCalWorkunits(calPlan);
        return AjaxResult.success();
    }

    private static void checkPlan(CalPlan calPlan) {
        List<CalShift> calShifts = calPlan.getCalShifts();
        ExceptionUtil.checkTrueThrowException(calShifts == null || CollectionUtil.isEmpty(calShifts), MessageUtils.message("cal.error.error2"));
        ExceptionUtil.checkTrueThrowException(calPlan.getStartDate() == null || calPlan.getEndDate() == null, MessageUtils.message("cal.error.error3"));
        ExceptionUtil.checkTrueThrowException(calPlan.getStartDate().getTime() > calPlan.getEndDate().getTime(), MessageUtils.message("cal.error.error4"));


        ExceptionUtil.checkTrueThrowException(calShifts.stream().filter(x ->
                (x.getEndTime() == null && x.getEndTime() == "") ||
                        (x.getStartTime() == null && x.getStartTime() == "")
        ).count() > 0, MessageUtils.message("cal.error.error5"));


        String shiftType = calPlan.getShiftType();
        int size = calShifts.size();
        ExceptionUtil.checkTrueThrowException(UserConstants.CAL_SHIFT_TYPE_SINGLE.equals(shiftType) && size != 1, MessageUtils.message("cal.error.error6"));
        ExceptionUtil.checkTrueThrowException(UserConstants.CAL_SHIFT_TYPE_TWO.equals(shiftType) && size != 2, MessageUtils.message("cal.error.error7"));
        ExceptionUtil.checkTrueThrowException(UserConstants.CAL_SHIFT_TYPE_THREE.equals(shiftType) && size != 3, MessageUtils.message("cal.error.error8"));

        Date startDate = calPlan.getStartDate();
        Date endDate = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String startDateFormat = sdf.format(startDate);
        String endDateFormat = sdf.format(startDate);
        Set<Integer> collect2 = calShifts.stream().map(CalShift::getOrderNum).filter(Objects::nonNull).collect(Collectors.toSet());
        ExceptionUtil.checkTrueThrowException(collect2.size() != calShifts.size(), MessageUtils.message("cal.error.error9"));

        for (CalShift calShift : calShifts) {
            String shiftName = calShift.getShiftName();
            endDate = formatShiftDate(endDateFormat, calShift.getEndTime());
            startDate = formatShiftDate(startDateFormat, calShift.getStartTime());
            if (Objects.equals(shiftName, "夜班")) {


                if (startDate.getTime() > endDate.getTime()) {
                    startDate = calPlan.getStartDate();
                    Date nextDay = DateUtils.getNextDay(startDate);

                    //今天日期
                    sdf = new SimpleDateFormat("yyyy-MM-dd");
                    endDateFormat = sdf.format(nextDay);
                    endDate = formatShiftDate(endDateFormat, calShift.getEndTime());
                }
            }


            List<CalShift> breakTimeList = calShift.getBreakTimeList();
            if (CollectionUtil.isNotEmpty(breakTimeList)) {
                Set<Integer> collect = breakTimeList.stream().map(CalShift::getOrderNum).filter(Objects::nonNull).collect(Collectors.toSet());
                ExceptionUtil.checkTrueThrowException(collect.size() != breakTimeList.size(), MessageUtils.message("cal.error.error10"));

                ExceptionUtil.checkTrueThrowException(endDate.getTime() <= startDate.getTime(),
                        MessageUtils.message("cal.error.error11", shiftName));


                if (breakTimeList.size() == 2) {
                    CalShift calShift1 = breakTimeList.get(0);
                    Date breakStartDate1 = formatShiftDate(startDateFormat, calShift1.getBreakStartTime());
                    Date breakEndDate1 = formatShiftDate(endDateFormat, calShift1.getBreakEndTime());


                    CalShift calShift2 = breakTimeList.get(1);
                    Date breakStartDate2 = formatShiftDate(startDateFormat, calShift2.getBreakStartTime());
                    Date breakEndDate2 = formatShiftDate(endDateFormat, calShift2.getBreakEndTime());


                    ExceptionUtil.checkTrueThrowException(
                            (breakEndDate1.getTime() <= breakStartDate1.getTime()) ||
                                    (breakEndDate2.getTime() <= breakStartDate2.getTime()),
                            MessageUtils.message("cal.error.error12", shiftName));


                    ExceptionUtil.checkTrueThrowException(
                            (breakEndDate1.getTime() > breakEndDate2.getTime() || breakStartDate1
                                    .getTime() > breakStartDate2.getTime()) ||
                                    !DateUtils.isTimePeriodOverlapping(breakStartDate1, breakEndDate1, breakStartDate2, breakEndDate2) ||
                                    DateUtils.hasTimeOverlap(breakStartDate1, breakEndDate1, breakStartDate2, breakEndDate2),
                            MessageUtils.message("cal.error.error13", shiftName));

                    ExceptionUtil.checkTrueThrowException(
                            (breakStartDate1.getTime() < startDate.getTime()) ||
                                    (breakStartDate2.getTime() < startDate.getTime()),
                            MessageUtils.message("cal.error.error14", shiftName));


                    ExceptionUtil.checkTrueThrowException(
                            (breakEndDate1.getTime() > endDate.getTime()) ||
                                    (breakEndDate2.getTime() > endDate.getTime()),
                            MessageUtils.message("cal.error.error15", shiftName));

                }


                if (breakTimeList.size() == 1) {
                    CalShift calShift1 = breakTimeList.get(0);
                    Date breakStartDate1 = formatShiftDate(startDateFormat, calShift1.getBreakStartTime());
                    Date breakEndDate1 = formatShiftDate(endDateFormat, calShift1.getBreakEndTime());
                    ExceptionUtil.checkTrueThrowException(breakEndDate1.getTime() <= breakStartDate1.getTime(), MessageUtils.message("cal.error.error16", shiftName));

                    ExceptionUtil.checkTrueThrowException(breakStartDate1.getTime() < startDate.getTime(), MessageUtils.message("cal.error.error14", shiftName));
                    ExceptionUtil.checkTrueThrowException(breakEndDate1.getTime() > endDate.getTime(), MessageUtils.message("cal.error.error15", shiftName));
                }
            }


        }
    }

    /**
     * 发布排班
     */
    @ApiOperation("排班计划修改完成")
    @PreAuthorize("@ss.hasPermi('mes:cal:calplan:edit')")
    @Log(title = "排班计划修改完成", businessType = BusinessType.UPDATE)
    @PutMapping("/releasePlan")
    public AjaxResult releasePlan(@RequestBody CalPlan calPlan) {
        checkPlan(calPlan);

        ExceptionUtil.checkTrueThrowException(!UserConstants.ORDER_STATUS_CONFIRMED.equals(calPlan.getStatus()), MessageUtils.message("cal.error.error17"));
        calPlan.setUpdateBy(SecurityUtils.getUsername());
        calPlan.setUpdateTime(DateUtils.getNowDate());
        calPlanService.releasePlan(calPlan);
        return AjaxResult.success();
    }

    /**
     * 删除排班计划
     */
    @PreAuthorize("@ss.hasPermi('mes:cal:calplan:remove')")
    @Log(title = "排班计划", businessType = BusinessType.DELETE)
    @Transactional
    @DeleteMapping("/{planIds}")
    public AjaxResult remove(@PathVariable Long[] planIds) {
        for (Long planId : planIds) {
            //状态判断
            CalPlan plan = calPlanService.selectCalPlanByPlanId(planId);
            if (!UserConstants.ORDER_STATUS_PREPARE.equals(plan.getStatus())) {
                return AjaxResult.error(MessageUtils.message("cal.error.error18"));
            }
            calShiftService.deleteByPlanId(planId);
            calPlanTeamService.deleteByPlanId(planId);
        }
        return toAjax(calPlanService.deleteCalPlanByPlanIds(planIds));
    }

    /**
     * 导出排班计划列表
     */
    @PreAuthorize("@ss.hasPermi('mes:cal:calplan:export')")
    @Log(title = "排班计划", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, CalPlan calPlan) throws IOException {
        List<CalPlan> list = calPlanService.selectCalPlanList(calPlan);
        List<CalPlanExcelExport> exportList = BeanUtil.copyToList(list, CalPlanExcelExport.class);
        ExcelWriter.write(response, CalPlanExcelExport.class, exportList);
    }

}
