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

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import cn.ezhizao.common.exception.ServiceException;
import cn.ezhizao.common.utils.SecurityUtils;
import cn.ezhizao.project.business.channel.domain.BizChannel;
import cn.ezhizao.project.business.channel.service.IBizChannelService;
import cn.ezhizao.project.business.company.domain.BizCompany;
import cn.ezhizao.project.business.company.service.IBizCompanyService;
import cn.ezhizao.project.business.company.service.impl.BizCompanyServiceImpl;
import cn.ezhizao.project.business.order.domain.*;
import cn.ezhizao.project.business.order.service.IBizArchiveInputDetailProcessService;
import cn.ezhizao.project.business.order.service.IBizArchiveInputDetailService;
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.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.io.IoUtil;
import cn.hutool.poi.excel.ExcelWriter;
import org.apache.commons.io.IOUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.core.io.ClassPathResource;
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.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.ezhizao.framework.aspectj.lang.annotation.Log;
import cn.ezhizao.framework.aspectj.lang.enums.BusinessType;
import cn.ezhizao.project.business.order.service.IBizArchiveInputService;
import cn.ezhizao.framework.web.controller.BaseController;
import cn.ezhizao.framework.web.domain.AjaxResult;
import cn.ezhizao.common.utils.poi.ExcelUtil;
import cn.ezhizao.framework.web.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;


/**
 * 档案入库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;

    /**
     * 查询档案入库列表
     */
    @PreAuthorize("@ss.hasPermi('business:archive:order:list')")
    @GetMapping("/list")
    public TableDataInfo list(BizArchiveInput 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);
        return getDataTable(list);
    }

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

    /**
     * 获取档案入库详细信息
     */
    @PreAuthorize("@ss.hasPermi('business:archive:order:query')")
    @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)
    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)
    public AjaxResult verify(@RequestBody BizArchiveInput bizArchiveInput) {
        return toAjax(bizArchiveInputService.verify(bizArchiveInput));
    }

    @PreAuthorize("@ss.hasPermi('business:archive:order:alter')")
    @PostMapping("/alter")
    @Log(title = "合同变更", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult alter(@RequestBody BizArchiveInput bizArchiveInput) {
        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) {
        bizArchiveInput = getById(bizArchiveInput.getId());
        bizArchiveInput.setDissolution(1);
        bizArchiveInput.setStatus(9);
        // 任务全部 停止
        boolean status = bizArchiveInputService.stopWorkOrder(bizArchiveInput);
        bizArchiveInput.setDissolution(1);
        return toAjax(status && bizArchiveInputService.updateById(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);
            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) {
        // 假设是单次任务判断删掉的任务是否已开始
        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 -> e.getId().equals(l.getId()))) {
                delList.add(l);
                delProcess.addAll(l.getProcesses());
            } else {
                BizArchiveInputDetail newItem = newBizArchiveInput.getDetails().stream().filter(v -> v.getId().equals(l.getId())).findFirst().orElse(new BizArchiveInputDetail());
                delProcess.addAll(l.getProcesses().stream().filter(v -> newItem.getProcesses().stream().noneMatch(e -> e.getId().equals(v.getId()))).collect(Collectors.toList()));
                if (newBizArchiveInput.getServiceType().equals(1)) {
                    if ((newItem.getFreeNum() + newItem.getServiceNum()) != (l.getServiceNum() + l.getFreeNum())) {
                        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("存在任务已完成，不能删除合同明细");
            }
            // 假设是循环任务判断修改数量的任务是否和已完成的任务数量相符
            if (!changeList.isEmpty() && !bizArchiveInputService.checkWorkOrderChangeStatus(changeList)) {
                throw new ServiceException("修改任务月数小于已完成月数。");
            }
        }
        return true;
    }

    @Log(title = "合同导入", businessType = BusinessType.IMPORT)
    @PreAuthorize("@ss.hasPermi('business:archive:order:import')")
    @PostMapping("/importLoop")
    public AjaxResult importLoop(MultipartFile file) throws Exception {
        ExcelUtil<OrderExcelImportLoopModel> util = new ExcelUtil<>(OrderExcelImportLoopModel.class);
        List<OrderExcelImportLoopModel> orderList = util.importExcel(file.getInputStream());
        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());
        String message = bizArchiveInputService.importOnce(orderList, SecurityUtils.getUserId(), getTenantId() == null ? 0 : getTenantId());
        return success(message);
    }

    @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();
            }
        }
    }
}
