package cn.ezhizao.project.business.order.controller;

import cn.ezhizao.common.exception.ServiceException;
import cn.ezhizao.common.utils.SecurityUtils;
import cn.ezhizao.common.utils.poi.ExcelUtil;
import cn.ezhizao.framework.aspectj.lang.annotation.Excel;
import cn.ezhizao.framework.aspectj.lang.annotation.Log;
import cn.ezhizao.framework.aspectj.lang.annotation.distributedLock;
import cn.ezhizao.framework.aspectj.lang.enums.BusinessType;
import cn.ezhizao.framework.web.controller.BaseController;
import cn.ezhizao.framework.web.domain.AjaxResult;
import cn.ezhizao.framework.web.page.TableDataInfo;
import cn.ezhizao.project.business.channel.domain.BizChannel;
import cn.ezhizao.project.business.channel.service.IBizChannelService;
import cn.ezhizao.project.business.collection.domain.BizCollectionDetail;
import cn.ezhizao.project.business.collection.service.IBizCollectionDetailService;
import cn.ezhizao.project.business.company.domain.BizCompany;
import cn.ezhizao.project.business.company.service.IBizCompanyService;
import cn.ezhizao.project.business.order.domain.*;
import cn.ezhizao.project.business.order.domain.vo.InputVo;
import cn.ezhizao.project.business.order.domain.vo.TimeVo;
import cn.ezhizao.project.business.order.service.IBizArchiveInputDetailProcessService;
import cn.ezhizao.project.business.order.service.IBizArchiveInputDetailService;
import cn.ezhizao.project.business.order.service.IBizArchiveInputService;
import cn.ezhizao.project.business.taskType.domain.BizTaskType;
import cn.ezhizao.project.business.taskType.domain.BizTaskTypeDetail;
import cn.ezhizao.project.business.taskType.service.IBizTaskTypeDetailService;
import cn.ezhizao.project.business.taskType.service.IBizTaskTypeService;
import cn.ezhizao.project.business.workOrder.domain.BizWorkOrder;
import cn.ezhizao.project.business.workOrder.domain.BizWorkOrderDetail;
import cn.ezhizao.project.business.workOrder.domain.BizWorkOrderRecord;
import cn.ezhizao.project.business.workOrder.service.IBizWorkOrderDetailService;
import cn.ezhizao.project.business.workOrder.service.IBizWorkOrderRecordService;
import cn.ezhizao.project.business.workOrder.service.IBizWorkOrderService;
import cn.ezhizao.project.system.domain.SysFileStorage;
import cn.ezhizao.project.system.domain.SysUser;
import cn.ezhizao.project.system.service.ISysFileStorageService;
import cn.ezhizao.project.system.service.ISysUserService;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.core.io.ResourceLoader;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 档案入库Controller
 *
 * @author ruoyi
 * @date 2023-10-16
 */
@RestController
@RequestMapping("/business/archive/order")
public class BizArchiveInputController extends BaseController {
    @Resource
    ResourceLoader resourceLoader;
    @Resource
    private IBizArchiveInputService bizArchiveInputService;
    @Resource
    private IBizArchiveInputDetailService archiveInputDetailService;
    @Resource
    private IBizArchiveInputDetailProcessService archiveInputDetailProcessService;
    @Resource
    private IBizTaskTypeService taskTypeService;
    @Resource
    private IBizTaskTypeDetailService taskTypeDetailService;
    @Resource
    private IBizCompanyService companyService;
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private IBizChannelService channelService;
    @Resource
    private ISysFileStorageService fileStorageService;
    @Resource
    private IBizWorkOrderService workOrderService;
    @Resource
    private IBizCollectionDetailService bizCollectionDetailService;

    @Resource
    private IBizWorkOrderDetailService bizWorkOrderDetailService;

    @Resource
    private IBizWorkOrderRecordService workOrderRecordService;

    @Resource
    private IBizArchiveInputDetailService bizArchiveInputDetailServiceService;


    /**
     * 查询档案入库列表
     */
    @PreAuthorize("@ss.hasPermi('business:archive:order:list')")
    @GetMapping("/list")
    public TableDataInfo list(InputVo bizArchiveInput) throws NoSuchFieldException, IllegalAccessException {
        setTenantId(bizArchiveInput);
        //分页
        startPage();
        //排序
        startOrderBy();
        //根据客户名称模糊查询去除两边空格
        if (bizArchiveInput.getCompanyName() != null) {
            if (!bizArchiveInput.getCompanyName().equals(""))
                bizArchiveInput.setCompanyName(bizArchiveInput.getCompanyName().trim());
        }
//        List<BizArchiveInput> list = bizArchiveInputService.getList(bizArchiveInput);
        List<BizArchiveInput> list = bizArchiveInputService.getListByInput(bizArchiveInput);

        return getDataTable(list);
    }

    @PreAuthorize("@ss.hasPermi('business:archive:order:list')")
    @GetMapping("/list2")
    public TableDataInfo list2(InputVo bizArchiveInput) throws NoSuchFieldException, IllegalAccessException {
        setTenantId(bizArchiveInput);
        //分页
        startPage();
        //排序
        startOrderBy();
        //根据客户名称模糊查询去除两边空格
        if (bizArchiveInput.getCompanyName() != null) {
            if (!bizArchiveInput.getCompanyName().equals(""))
                bizArchiveInput.setCompanyName(bizArchiveInput.getCompanyName().trim());
        }
//        List<BizArchiveInput> list = bizArchiveInputService.getList(bizArchiveInput);
        List<BizArchiveInput> list = bizArchiveInputService.getListByInput(bizArchiveInput);
        for (BizArchiveInput item : list) {
            Integer serviceType = item.getServiceType();
            if (serviceType.equals(1)) {
                List<BizArchiveInputDetail> details = archiveInputDetailService.list(new LambdaQueryWrapper<>(BizArchiveInputDetail.class).eq(BizArchiveInputDetail::getContractId, item.getId()));
                for (BizArchiveInputDetail detail : details) {
                    detail.setTaskTypeName(taskTypeService.getById(detail.getTaskTypeId()).getName());
                }
                item.setRemark(details.stream().map(BizArchiveInputDetail::getTaskTypeName).collect(Collectors.joining(",")));
            }

        }
        return getDataTable(list);
    }

    /**
     * 导出档案入库列表
     */
    @PreAuthorize("@ss.hasPermi('business:archive:order:export')")
    @Log(title = "档案入库", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, InputVo bizArchiveInput) throws NoSuchFieldException, IllegalAccessException {
        setTenantId(bizArchiveInput);
        List<BizArchiveInput> list = bizArchiveInputService.getListByInput(bizArchiveInput);
        ExcelUtil<BizArchiveInput> util = new ExcelUtil<BizArchiveInput>(BizArchiveInput.class);
        util.exportExcel(response, list, "档案入库数据");
    }

    /**
     * 获取档案入库详细信息
     */
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(getById(id));
    }

    /**
     * 新增档案入库
     */
    @PreAuthorize("@ss.hasPermi('business:archive:order:add')")
    @Log(title = "档案入库", businessType = BusinessType.INSERT)
    @PostMapping
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody BizArchiveInput bizArchiveInput) throws NoSuchFieldException, IllegalAccessException {
        setTenantId(bizArchiveInput);
        return toAjax(bizArchiveInputService.save(bizArchiveInput));
    }

    /**
     * 修改档案入库
     */
    @PreAuthorize("@ss.hasPermi('business:archive:order:edit')")
    @Log(title = "档案入库", businessType = BusinessType.UPDATE)
    @PutMapping
    @Transactional(rollbackFor = Exception.class)
    @distributedLock(prefix = "crmInputAdd",key = "@tenantId")
    public AjaxResult edit(@RequestBody BizArchiveInput bizArchiveInput) throws NoSuchFieldException, IllegalAccessException {
        setTenantId(bizArchiveInput);
        return toAjax(bizArchiveInputService.updateById(bizArchiveInput));
    }

    /**
     * 删除档案入库
     */
    @PreAuthorize("@ss.hasPermi('business:archive:order:remove')")
    @Log(title = "档案入库", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult remove(@PathVariable List<Long> ids) {
        // 判断是否已审核审核通过不能删
        return toAjax(bizArchiveInputService.removeBatchByIds(ids));
    }

    @PreAuthorize("@ss.hasPermi('business:archive:order:query')")
    @GetMapping("/initTaskTypes")
    public AjaxResult initTaskTypes() {
        List<BizTaskType> loopTasks = taskTypeService.query().eq("type", 1).list();
        List<BizTaskType> onceTasks = taskTypeService.query().eq("type", 2).list();
        List<BizTaskTypeDetail> details = taskTypeDetailService.list();
        onceTasks.forEach(l -> l.setProcesses(details.stream().filter(v -> v.getTaskTypeId().equals(l.getId())).collect(Collectors.toList())));
        Map<String, Object> map = new HashMap<>();
        map.put("loopTasks", loopTasks);
        map.put("onceTasks", onceTasks);
        return success(map);
    }

    @PreAuthorize("@ss.hasPermi('business:archive:order:verify')")
    @PostMapping("/verify")
    @Log(title = "档案审核", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
    @distributedLock(prefix = "crmInputVerify",key = "#bizArchiveInput.id")
    public AjaxResult verify(@RequestBody BizArchiveInput bizArchiveInput) {
        boolean flag = bizArchiveInputService.verify(bizArchiveInput);
        bizArchiveInputService.saveDetailMonth(bizArchiveInput);
        return flag ? success() : error("审核失败，请刷新页面获取最新数据");
    }

    @PreAuthorize("@ss.hasPermi('business:archive:order:alter')")
    @PostMapping("/alter")
    @Log(title = "合同变更", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
    @distributedLock(prefix = "crmInputAlter",key = "#bizArchiveInput.id")
    public AjaxResult alter(@RequestBody BizArchiveInput bizArchiveInput) {
        Long userId = SecurityUtils.getUserId();
        //防止前端没传明细id
        List<BizArchiveInputDetail> list = archiveInputDetailService
                .list(new LambdaQueryWrapper<BizArchiveInputDetail>().eq(BizArchiveInputDetail::getContractId, bizArchiveInput.getId()));
        for (BizArchiveInputDetail detail : bizArchiveInput.getDetails()) {
            if (detail.getFreeNum() == null) {
                detail.setFreeNum(0);
            }
            for (BizArchiveInputDetail bizArchiveInputDetail : list) {
                if (detail.getTaskTypeId().equals(bizArchiveInputDetail.getTaskTypeId())) {
                    detail.setId(bizArchiveInputDetail.getId());
                }
            }
        }

        BizArchiveInput oldBizArchiveInput = getById(bizArchiveInput.getId());
        checkAlter(bizArchiveInput, oldBizArchiveInput);
        setNullId(oldBizArchiveInput);
        boolean status = bizArchiveInputService.save(oldBizArchiveInput);
        bizArchiveInput.setVerifyStatus(0);
        bizArchiveInput.setStatus(8);
        // 判断是否有任务被删除
        return toAjax(status && bizArchiveInputService.updateById(bizArchiveInput));
    }

    @PreAuthorize("@ss.hasPermi('business:archive:order:dissolution')")
    @PostMapping("/dissolution")
    @Log(title = "合同解除", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult dissolution(@RequestBody BizArchiveInput bizArchiveInput) {
        boolean b = relieveCheck(bizArchiveInput );
        if (!b && bizArchiveInput.getServiceType()==1) {
            throw new RuntimeException("解除失败，请先解除最后签约合同");
        }

        bizArchiveInput = getById(bizArchiveInput.getId());
        bizArchiveInput.setDissolution(1);
        bizArchiveInput.setStatus(9);
        // 任务全部 停止
        boolean status = bizArchiveInputService.stopWorkOrder(bizArchiveInput);
        bizArchiveInput.setDissolution(1);
        //传入当前时间为解除时间
        bizArchiveInput.setDissDate(new Date(System.currentTimeMillis()));
        return toAjax(status && bizArchiveInputService.updateById(bizArchiveInput)
                && bizArchiveInputService.saveDetailMonth(bizArchiveInput));
    }


    private BizArchiveInput getById(Long id) {
        BizArchiveInput condition = new BizArchiveInput();
        condition.setId(id);
        BizArchiveInput bizArchiveInput = bizArchiveInputService.getList(condition).stream().findFirst().orElse(null);
        if (bizArchiveInput != null && bizArchiveInput.getReferrerDataSource() != null) {
            switch (bizArchiveInput.getReferrerDataSource()) {
                case "company":
                    BizCompany source = companyService.getById(bizArchiveInput.getSourceId());
                    bizArchiveInput.setSourceName(source != null ? source.getName() : "");
                    break;
                case "employee":
                    SysUser sysUser = sysUserService.selectUserById(bizArchiveInput.getSourceId());
                    bizArchiveInput.setSourceName(sysUser != null ? sysUser.getNickName() : "");
                    break;
                case "channel":
                    BizChannel channel = channelService.getById(bizArchiveInput.getSourceId());
                    bizArchiveInput.setSourceName(channel != null ? channel.getName() : "");
                    break;
                default:
                    break;
            }
        }
        if (bizArchiveInput != null) {
            BizArchiveInputDetail conditionDetail = new BizArchiveInputDetail();
            conditionDetail.setContractId(bizArchiveInput.getId());
            BizArchiveInputDetailProcess conditionProcess = new BizArchiveInputDetailProcess();
            List<SysFileStorage> sysFileStorages = fileStorageService.query().eq("master_table_name", "biz_archive_input").eq("master_id", bizArchiveInput.getId()).list();
            List<BizArchiveInputDetail> details = archiveInputDetailService.getList(conditionDetail);
            for (BizArchiveInputDetail detail : details) {
                BizWorkOrderDetail one = bizWorkOrderDetailService.getOne(new LambdaQueryWrapper<BizWorkOrderDetail>()
                        .eq(BizWorkOrderDetail::getContractDetailId, detail.getId())
                        .eq(BizWorkOrderDetail::getIsStop, 0)
                        .eq(BizWorkOrderDetail::getTaskTypeId, detail.getTaskTypeId()));
                List<BizWorkOrderRecord> list = null;
                if (one != null) {
                    list = workOrderRecordService.list(new LambdaQueryWrapper<BizWorkOrderRecord>()
                            .eq(BizWorkOrderRecord::getWorkOrderId, one.getWorkOrderId()));
                    detail.setDisabled(CollectionUtils.isNotEmpty(list));
                }
                if (bizArchiveInput.getServiceType() == 1) {
                    TimeVo time = getTime(detail.getContractId(), detail.getId(), detail.getTaskTypeId(), detail.getCompanyId());
                    if (time != null) {
                        detail.setTimeVo(time);
                        detail.setMonthDisabled(list != null &&
                                list.stream()
                                        .anyMatch(record ->
                                                DateTime.of(detail.getTimeVo().getStartTime())
                                                        .toString("yyyyMM")
                                                        .compareTo(record.getYear() + record.getMonth()) <= 0));
                    }
                }
            }

            List<BizArchiveInputDetailProcess> processes = archiveInputDetailProcessService.getList(conditionProcess);
            details.forEach(l -> l.setProcesses(processes.stream().filter(v -> v.getContractDetailId().equals(l.getId())).collect(Collectors.toList())));
            bizArchiveInput.setDetails(details);
            bizArchiveInput.setFiles(sysFileStorages);
        }
        return bizArchiveInput;
    }

    private void setNullId(BizArchiveInput bizArchiveInput) {
        bizArchiveInput.setFromId(bizArchiveInput.getId());
        bizArchiveInput.setId(null);
        bizArchiveInput.getDetails().forEach(l -> {
            l.setFromId(l.getId());
            l.setId(null);
            l.getProcesses().forEach(v -> {
                v.setFromId(v.getId());
                v.setId(null);
            });
        });
        bizArchiveInput.getFiles().forEach(l -> {
            l.setId(null);
        });
    }

    private boolean checkAlter(BizArchiveInput newBizArchiveInput, BizArchiveInput oldArchiveInput) {
        boolean result = true;
        // 假设是单次任务判断删掉的任务是否已开始
        if (!newBizArchiveInput.getServiceType().equals(oldArchiveInput.getServiceType())) {
            throw new ServiceException("变更任务和原任务类型不相符");
        }
        List<BizArchiveInputDetail> delList = new ArrayList<>();
//        oldArchiveInput.getDetails().stream().filter(v -> newBizArchiveInput.getDetails().stream().anyMatch(e -> e.getId().equals(v.getId()))).collect(Collectors.toList())
        List<BizArchiveInputDetailProcess> delProcess = new ArrayList<>();
        List<BizArchiveInputDetail> changeList = new ArrayList<>();
        List<BizArchiveInputDetailProcess> changeProcess = new ArrayList<>();
        oldArchiveInput.getDetails().forEach(l -> {
            if (newBizArchiveInput.getDetails().stream().noneMatch(e -> l.getId().equals(e.getId()))) {
                delList.add(l);
                delProcess.addAll(l.getProcesses());
            } else {
                BizArchiveInputDetail newItem = newBizArchiveInput.getDetails().stream().filter(v -> l.getId().equals(v.getId())).findFirst().orElse(new BizArchiveInputDetail());
                delProcess.addAll(l.getProcesses().stream()
                        .filter(v -> newItem.getProcesses().stream()
                                .noneMatch(e -> e.getId() != null && e.getId().equals(v.getId()))).collect(Collectors.toList()));
                if (newBizArchiveInput.getServiceType().equals(1)) {
                    boolean a = (newItem.getFreeNum() + newItem.getServiceNum()) != (l.getServiceNum() + l.getFreeNum());
                    boolean b = (newItem.getPrice().subtract(newItem.getDiscountAmount())).compareTo(l.getPrice().subtract(l.getDiscountAmount())) != 0;
                    if (a || b) {
                        changeList.add(l);
                    }
                }
            }
        });
        // 假设是单次任务判断删掉的任务是否已开始
        if (newBizArchiveInput.getServiceType().equals(2)) {
            if (!(delProcess.isEmpty() || bizArchiveInputService.checkWorkOrderStatusProcess(delProcess))) {
                throw new ServiceException("存在任务已完成，不能删除该合同明细。");
            }
//            newBizArchiveInput.get
        }
        if (newBizArchiveInput.getServiceType().equals(1)) {
            // 假设是循环任务判断判断删掉的任务是否已经开始
            if (!delList.isEmpty() && !bizArchiveInputService.checkWorkOrderStatus(delList)) {
                throw new ServiceException("存在任务已完成或填报，不能删除或修改该合同明细");
            }
            //任务开始就不可以修改
            for (BizArchiveInputDetail item : changeList) {
                BizWorkOrderDetail one = bizWorkOrderDetailService.getOne(new LambdaQueryWrapper<BizWorkOrderDetail>()
                        .eq(BizWorkOrderDetail::getContractDetailId, item.getId())
                        .eq(BizWorkOrderDetail::getIsStop, 0));

                BizArchiveInputDetail newInputDetail = newBizArchiveInput.getDetails().stream().filter(detail->detail.getId().equals(item.getId())).findFirst().orElse(new BizArchiveInputDetail());;
                boolean b = (item.getPrice().subtract(item.getDiscountAmount())).compareTo(newInputDetail.getPrice().subtract(newInputDetail.getDiscountAmount())) != 0;
                if(b){
                    List<BizCollectionDetail> collectionDetailList = bizCollectionDetailService.list(new LambdaQueryWrapper<BizCollectionDetail>()
                            .eq(BizCollectionDetail::getContractId, newBizArchiveInput.getId())
                            .eq(BizCollectionDetail::getContractDetailId, item.getId())
                            .eq(BizCollectionDetail::getTaskTypeId, item.getTaskTypeId()));
                    if (CollectionUtils.isNotEmpty(collectionDetailList)) {
                        throw new RuntimeException("您已经收款，无法修改合同价格！");
                    }
                }
                //通过明细查询workorderID 进而查询record表
                if (one != null) {
                    Long workOrderId = one.getWorkOrderId();
                    List<BizWorkOrderRecord> list = workOrderRecordService.list(new LambdaQueryWrapper<BizWorkOrderRecord>()
                            .eq(BizWorkOrderRecord::getWorkOrderId, workOrderId));

                    //续签时当前时间段如果没有工单则可以修改
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                    List<LocalDate> datesList = list.stream().map(x -> {
                        String formattedMonth = String.format("%02d", Integer.valueOf(x.getMonth()).intValue());
                        return LocalDate.parse(x.getYear() + "-" + formattedMonth + "-01", formatter);
                    }).collect(Collectors.toList());
                    TimeVo time = getTime(item.getContractId(), item.getId(), item.getTaskTypeId(), newBizArchiveInput.getCompanyId());
                    if (time != null && time.getStartTime() != null) {
                        String startM = format.format(time.getStartTime());
                        String endM = format.format(time.getEndTime());
                        LocalDate startDate = LocalDate.parse(startM, formatter);
                        LocalDate endDate = LocalDate.parse(endM, formatter);
                        result = isAnyDateInRange(datesList, startDate, endDate);
                    }

                    if (CollectionUtils.isNotEmpty(list) && result) {
                        throw new ServiceException("存在已开始的任务，不能修改该合同明细");
                    }

                }
            }

            // 假设是循环任务判断修改数量的任务是否和已完成的任务数量相符
//            if (!changeList.isEmpty() && !bizArchiveInputService.checkWorkOrderChangeStatus(changeList)) {
//                throw new ServiceException("修改任务月数小于已完成月数。");
//            }
            for (BizArchiveInputDetail item : delList) {

                List<BizCollectionDetail> list = bizCollectionDetailService.list(new LambdaQueryWrapper<BizCollectionDetail>()
                        .eq(BizCollectionDetail::getContractId, newBizArchiveInput.getId())
                        .eq(BizCollectionDetail::getContractDetailId, item.getId())
                        .eq(BizCollectionDetail::getTaskTypeId, item.getTaskTypeId()));
                if (CollectionUtils.isNotEmpty(list)) {
                    throw new RuntimeException("已存在该任务类型的收款合同，无法删除");
                }
            }
        }
        return true;
    }

    public static boolean isAnyDateInRange(List<LocalDate> dates, LocalDate startDate, LocalDate endDate) {
        return dates.stream()
                .anyMatch(date -> !date.isBefore(startDate) && !date.isAfter(endDate));
    }

    @Log(title = "合同导入", businessType = BusinessType.IMPORT)
    @PreAuthorize("@ss.hasPermi('business:archive:order:import')")
    @PostMapping("/importLoop")
    @Transactional
    @distributedLock(prefix = "crmImportLoop",key = "@tenantId")
    public AjaxResult importLoop(MultipartFile file) throws Exception {
        ExcelUtil<OrderExcelImportLoopModel> util = new ExcelUtil<>(OrderExcelImportLoopModel.class);
        List<OrderExcelImportLoopModel> orderList = util.importExcel(file.getInputStream());
        // 获取 入Excel 表头字段
        List<String> excelHeaders = util.readExcelHeaders(file.getInputStream());
        //获取实体类字段
        List<String> names = getExcelAnnotatedFields(OrderExcelImportLoopModel.class);
        //如果不存在模板中的字段，返回错误
        if (!names.containsAll(excelHeaders)) {
            return error("导入数据与模板不匹配！");
        }
        String message = bizArchiveInputService.importLoop(orderList, SecurityUtils.getUserId(), getTenantId() == null ? 0 : getTenantId());
        return success(message);
    }

    @Log(title = "合同导入", businessType = BusinessType.IMPORT)
    @PreAuthorize("@ss.hasPermi('business:archive:order:import')")
    @PostMapping("/importOnce")
    public AjaxResult importOnce(MultipartFile file) throws Exception {

        ExcelUtil<OrderExcelImportOnceModel> util = new ExcelUtil<>(OrderExcelImportOnceModel.class);
        List<OrderExcelImportOnceModel> orderList = util.importExcel(file.getInputStream());
        // 获取 入Excel 表头字段
        List<String> excelHeaders = util.readExcelHeaders(file.getInputStream());
        //获取实体类字段
        List<String> names = getExcelAnnotatedFields(OrderExcelImportOnceModel.class);
        //如果不存在模板中的字段，返回错误
        if (!names.containsAll(excelHeaders)) {
            return error("导入数据与模板不匹配！");
        }
        String message = bizArchiveInputService.importOnce(orderList, SecurityUtils.getUserId(), getTenantId() == null ? 0 : getTenantId());
        return success(message);
    }

    public List<String> getExcelAnnotatedFields(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        List<String> result = new ArrayList<>();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Excel.class)) {
                Excel excelAnnotation = field.getAnnotation(Excel.class);
                String fieldName = excelAnnotation.name();
                result.add(fieldName);
            }
        }
        return result;
    }

    @Log(title = "合同模板导出", businessType = BusinessType.EXPORT)
    @PreAuthorize("@ss.hasPermi('business:archive:order:export')")
    @PostMapping("/exportLoopTemplate")
    public void exportLoopTemplate(HttpServletResponse response) throws Exception {
        org.springframework.core.io.Resource resource = resourceLoader.getResource("classpath:importTemplate/LoopOrderExcelTemplate.xlsx");
        if (resource.exists()) {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/vnd.ms-excel");
            String fileName = resource.getURI().toString().substring(resource.getURI().toString().lastIndexOf("/") + 1);
            response.setHeader("content-disposition", "attachment;filename=" + fileName);
            response.flushBuffer();
            //放弃使用直接获取文件的方式, 改成使用流的方式
            BufferedInputStream bis = new BufferedInputStream(resource.getInputStream());
            OutputStream os = response.getOutputStream();
            byte[] buffer = new byte[1024];
            int i = bis.read(buffer);
            while (i != -1) {
                os.write(buffer, 0, i);
                i = bis.read(buffer);
            }
            if (bis != null) {
                bis.close();
            }
        }
    }

    @Log(title = "合同模板导出", businessType = BusinessType.EXPORT)
    @PreAuthorize("@ss.hasPermi('business:archive:order:export')")
    @PostMapping("/exportOnceTemplate")
    public void exportOnceTemplate(HttpServletResponse response) throws Exception {
        org.springframework.core.io.Resource resource = resourceLoader.getResource("classpath:importTemplate/OnceOrderExcelTemplate.xlsx");
        if (resource.exists()) {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/vnd.ms-excel");
            String fileName = resource.getURI().toString().substring(resource.getURI().toString().lastIndexOf("/") + 1);
            response.setHeader("content-disposition", "attachment;filename=" + fileName);
            response.flushBuffer();
            //放弃使用直接获取文件的方式, 改成使用流的方式
            BufferedInputStream bis = new BufferedInputStream(resource.getInputStream());
            OutputStream os = response.getOutputStream();
            byte[] buffer = new byte[1024];
            int i = bis.read(buffer);
            while (i != -1) {
                os.write(buffer, 0, i);
                i = bis.read(buffer);
            }
            if (bis != null) {
                bis.close();
            }
        }
    }

    @Log(title = "合同审核前检测")
    @PreAuthorize("@ss.hasPermi('business:archive:order:verify')")
    @PostMapping("/verifyCheck")
    public AjaxResult verifyCheck(@RequestBody BizArchiveInput archiveInput) {
        // 判断是否是循环合同
        List<BizArchiveInput> list = bizArchiveInputService.getList(archiveInput);
        if (!list.isEmpty()) {
            BizArchiveInput item = list.get(0);
            if (item.getServiceType().equals(1)) {
                BizArchiveInputDetail conditions = new BizArchiveInputDetail();
                conditions.setContractId(item.getId());
                List<BizArchiveInputDetail> details = archiveInputDetailService.getList(conditions);
                List<BizArchiveInputDetail> checkResult = new ArrayList<>();
                // 判断循环工单是否有旧工单
                for (BizArchiveInputDetail detail : details) {
                    BizWorkOrder workOrder = workOrderService.query().eq("company_id", item.getCompanyId()).eq("task_type_id", detail.getTaskTypeId()).orderByDesc("end_month").eq("is_stop", 0).last("limit 1").one();
                    if (workOrder != null && workOrder.getEndMonth() != null) {
                        DateTime endMonth = DateTime.of(workOrder.getEndMonth());
                        if (workOrder.getTaskTypeId().equals(1L)) {
                            // 记账报税做前一个月的所以结束月为上上个月的要判断是否接着上个工单
                            if (DateTime.now().offset(DateField.MONTH, -2).toString("yyyyMM").compareTo(endMonth.toString("yyyyMM")) > 0) {
                                detail.setEndMonth(workOrder.getEndMonth());
                                checkResult.add(detail);
                            }
                        } else {
                            // 社保公积金还有返税申报是这个月的所以结束月是上个月的判断是否接上个工单。
                            if (DateTime.now().offset(DateField.MONTH, -1).toString("yyyyMM").compareTo(endMonth.toString("yyyyMM")) > 0) {
                                detail.setEndMonth(workOrder.getEndMonth());
                                checkResult.add(detail);
                            }
                        }
                    }
                }
                if (!checkResult.isEmpty()) {
                    return success(checkResult);
                }
            }
        }
        return success();
    }

    //获取当前合同工单起始结束区间
    public TimeVo getTime(Long contractId, Long contractDetailId, Long typeId, Long companyId) {
        //排序获取当前索引位置
        BizWorkOrderDetail one = bizWorkOrderDetailService.getOne(
                new LambdaQueryWrapper<BizWorkOrderDetail>()
                        .eq(BizWorkOrderDetail::getContractId, contractId)
                        .eq(BizWorkOrderDetail::getContractDetailId, contractDetailId)
                        .eq(BizWorkOrderDetail::getCompanyId, companyId)
                        .eq(BizWorkOrderDetail::getTaskTypeId, typeId).eq(BizWorkOrderDetail::getDeleted, 0));

        if (one == null) {
            return null;
        }
        Long workOrderId = one.getWorkOrderId();

        BizWorkOrder workOrder = workOrderService.getById(workOrderId);
        if (workOrder == null) {
            logger.error("获取工单失败");
            return null;
        }
        //一个工单对应多个工单详细，一个工单可以挂多个合同
        //获取工单对应的工单详细（里面的数据有一些是从合同写入的）需要用签约日期排序
        List<BizWorkOrderDetail> list = bizWorkOrderDetailService.selectByWorkOrderId(contractId,workOrderId,typeId);
        //合同详细id转成list
        List<Long> indexList = list.stream().map(m -> m.getContractDetailId()).collect(Collectors.toList());
        //确定当前索引元素
        //获取当前方法传入的合同详细id在列表中的位置
        int i = indexList.indexOf(contractDetailId);
        if (i == -1) {
            return null;
        }
        //当前元素所有月份
        BizWorkOrderDetail bizWorkOrderDetail = list.get(i);
        int monthNum = bizWorkOrderDetail.getFreeNum() + bizWorkOrderDetail.getServiceNum();
        //获取位置之前所有数据月数的和（设置结束月）
        //判断是不是第一个
        if (i == 0) {
            DateTime startMonth = DateTime.of(workOrder.getStartMonth());
            Date endMonth = startMonth.offset(DateField.MONTH, monthNum - 1).toSqlDate();
            return new TimeVo(workOrder.getStartMonth(), endMonth);
        } else {
            //中间的工单
            //获取起始时间 并获取 i 之前所有月数 相加为起始时间
            int totalNum = getMonthNum(i - 1, list);
            DateTime month = DateTime.of(workOrder.getStartMonth());
            Date startMonth = month.offset(DateField.MONTH, totalNum).toSqlDate();
            DateTime startMonthTemp = DateTime.of(startMonth);
            Date endMonth = startMonthTemp.offset(DateField.MONTH, monthNum - 1).toSqlDate();
            return new TimeVo(startMonth, endMonth);
        }

    }

    public static int getMonthNum(int i, List<BizWorkOrderDetail> list) {
        int total = 0;
        while (i >= 0) {
            BizWorkOrderDetail bizWorkOrderDetail = list.get(i);
            total += bizWorkOrderDetail.getFreeNum() + bizWorkOrderDetail.getServiceNum();
            i--;
        }
        return total;
    }

    public boolean relieveCheck(BizArchiveInput input) {
        boolean flag = false;
        //通过公司id 合同id taskId 查询  workOrderDetail 如果是最后一条则可以删除
        List<BizArchiveInputDetail> list = bizArchiveInputDetailServiceService.list(
                new LambdaQueryWrapper<BizArchiveInputDetail>()
                        .eq(BizArchiveInputDetail::getContractId, input.getId())
                        .eq(BizArchiveInputDetail::getDeleted, 0)
        );

        List<BizArchiveInputDetail> details = list;
        //代理记账
        BizWorkOrderDetail typeOne = null;
        //社保
        BizWorkOrderDetail typeTwo = null;
        //公积金
        BizWorkOrderDetail typeThree = null;
        //报税申报
        BizWorkOrderDetail typeFour = null;
        for (BizArchiveInputDetail detail : details) {
            BizWorkOrderDetail one = bizWorkOrderDetailService.getOne(new LambdaQueryWrapper<BizWorkOrderDetail>()
                    .eq(BizWorkOrderDetail::getContractId, input.getId())
                    .eq(BizWorkOrderDetail::getContractDetailId, detail.getId())
                    .eq(BizWorkOrderDetail::getTaskTypeId, detail.getTaskTypeId())
                    .eq(BizWorkOrderDetail::getDeleted, 0)
                    .eq(BizWorkOrderDetail::getCompanyId, input.getCompanyId())
            );
            if (detail.getTaskTypeId() == 1) {
                typeOne = one;
            } else if (detail.getTaskTypeId() == 2) {
                typeTwo = one;
            } else if (detail.getTaskTypeId() == 3) {
                typeThree = one;
            } else if (detail.getTaskTypeId() == 4) {
                typeFour = one;
            }
        }
        if (typeOne != null) {
            Long workOrderId = typeOne.getWorkOrderId();
            //获取时间最后一个
            List<BizWorkOrderDetail> list1 = bizWorkOrderDetailService.list(new LambdaQueryWrapper<BizWorkOrderDetail>()
                    .eq(BizWorkOrderDetail::getWorkOrderId, workOrderId)
                    .eq(BizWorkOrderDetail::getDeleted, 0)
                    .eq(BizWorkOrderDetail::getIsStop, 0)
                    .orderByDesc(BizWorkOrderDetail::getCreateTime)
            );
            for (BizWorkOrderDetail detail : list1) {
                Long contractId = detail.getContractId();
                Integer status = bizArchiveInputService.getById(contractId).getStatus();
                detail.setStatus(status);
            }
            BizWorkOrderDetail bizWorkOrderDetail = list1.stream().filter(m -> !m.getStatus().equals(9)).collect(Collectors.toList()).get(0);

            if (bizWorkOrderDetail.getId().equals(typeOne.getId())) {
                flag = true;
            } else {
                return false;
            }

        }
        if (typeTwo != null) {
            Long workOrderId = typeTwo.getWorkOrderId();
            //获取时间最后一个
            BizWorkOrderDetail bizWorkOrderDetail = bizWorkOrderDetailService.list(new LambdaQueryWrapper<BizWorkOrderDetail>()
                    .eq(BizWorkOrderDetail::getWorkOrderId, workOrderId)
                    .eq(BizWorkOrderDetail::getDeleted, 0)
                    .orderByDesc(BizWorkOrderDetail::getCreateTime)
            ).get(0);
            if (bizWorkOrderDetail.getId().equals(typeTwo.getId())) {
                flag = true;
            } else {
                return false;
            }

        }
        if (typeThree != null) {
            Long workOrderId = typeThree.getWorkOrderId();
            //获取时间最后一个
            BizWorkOrderDetail bizWorkOrderDetail = bizWorkOrderDetailService.list(new LambdaQueryWrapper<BizWorkOrderDetail>()
                    .eq(BizWorkOrderDetail::getWorkOrderId, workOrderId)
                    .eq(BizWorkOrderDetail::getDeleted, 0)
                    .orderByDesc(BizWorkOrderDetail::getCreateTime)
            ).get(0);
            if (bizWorkOrderDetail.getId().equals(typeThree.getId())) {
                flag = true;
            } else {
                return false;
            }

        }
        if (typeFour != null) {
            Long workOrderId = typeFour.getWorkOrderId();
            //获取时间最后一个
            BizWorkOrderDetail bizWorkOrderDetail = bizWorkOrderDetailService.list(new LambdaQueryWrapper<BizWorkOrderDetail>()
                    .eq(BizWorkOrderDetail::getWorkOrderId, workOrderId)
                    .eq(BizWorkOrderDetail::getDeleted, 0)
                    .orderByDesc(BizWorkOrderDetail::getCreateTime)
            ).get(0);
            if (bizWorkOrderDetail.getId().equals(typeFour.getId())) {
                flag = true;
            } else {
                return false;
            }
        }
        return flag;
    }
    @RequestMapping("/saveDetailMonth")
    public void saveDetailMonth(){
       List<BizArchiveInput> list =  bizArchiveInputService.query().list();
        list.forEach(bizArchiveInputService::saveDetailMonth);
    }
}
