package com.ximai.mes.pro.controller.proWorkOrder;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
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.exception.ServiceException;
import com.ximai.common.utils.MessageUtils;
import com.ximai.common.utils.data.ExceptionUtil;
import com.ximai.common.utils.data.StringUtils;
import com.ximai.common.utils.excel.ExcelWriter;
import com.ximai.mes.constant.WorkorderStatusEnum;
import com.ximai.mes.md.domain.MdProductBom;
import com.ximai.mes.md.service.IMdBaseInfoService;
import com.ximai.mes.md.service.IMdProductBomService;
import com.ximai.mes.pro.domain.ProWorkorderBomm;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkOrderSoDirective;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkOrderSoSizeItem;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkorder;
import com.ximai.mes.pro.domain.task.ProPackagePrintRecord;
import com.ximai.mes.pro.domain.task.ProTask;
import com.ximai.mes.pro.domain.vo.ProPackagePrintResult;
import com.ximai.mes.pro.domain.vo.ProWorkOrderProcessVo;
import com.ximai.mes.pro.domain.vo.ProWorkorderQuery;
import com.ximai.mes.pro.domain.vo.ProWorkorderVo;
import com.ximai.mes.pro.domain.vo.proWorkOrder.BuildPackageParams2;
import com.ximai.mes.pro.domain.vo.proWorkOrder.ProWorkorderPrintTab;
import com.ximai.mes.pro.domain.vo.proWorkOrder.WorkorderProofMakeProduction;
import com.ximai.mes.pro.dto.ProWorkorderExcelExport;
import com.ximai.mes.pro.mapper.proWorkOrder.ProWorkOrderProcessMapper;
import com.ximai.mes.pro.service.IProWorkorderBomService;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkOrderSoDirectiveService;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkOrderSoSizeItemService;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkorderService;
import com.ximai.mes.pro.service.task.IProTaskService;
import com.ximai.system.strategy.AutoCodeUtil;
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.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * 生产工单Controller
 *
 * @date 2022-05-09
 */
@RestController
@RequestMapping("/mes/pro/workorder")
public class ProWorkorderController extends BaseController {
    @Autowired
    private IProWorkorderService proWorkorderService;
    @Resource
    private ProWorkOrderProcessMapper proWorkOrderProcessMapper;

    @Autowired
    private IProWorkorderBomService proWorkorderBomService;

    @Autowired
    private IMdProductBomService mdProductBomService;

    @Autowired
    private IProTaskService proTaskService;

    @Autowired
    private IProWorkOrderSoSizeItemService proWorkOrderSoSizeItemService;

    @Autowired
    private IProWorkOrderSoDirectiveService proWorkOrderSoDirectiveService;

    @Autowired
    private IMdBaseInfoService mdBaseInfoService;


    @Autowired
    AutoCodeUtil autoCodeUtil;

    /**
     * 查询生产工单列表
     */
    @ApiOperation("工单查询")
    @GetMapping("/list")
    public TableDataInfo<ProWorkorder> list(ProWorkorderQuery proWorkorder) {
        startPage();
        List<ProWorkorder> list = proWorkorderService.selectProWorkorderList(proWorkorder);
        return getDataTable(list);
    }

    /**
     * 查询待排产生产工单列表
     */
    @ApiOperation("查询待排产生产工单列表")
    @GetMapping("/scheduleList")
    public TableDataInfo<ProWorkorder> scheduleList(ProWorkorderQuery proWorkorder) {
        startPage();
        QueryWrapper<ProWorkorder> query = new QueryWrapper<>();
        query.like(StringUtils.isNotEmpty(proWorkorder.getOrderCode()), "t1.order_code",
                proWorkorder.getOrderCode());
        query.like(StringUtils.isNotEmpty(proWorkorder.getOrderSerial()), "t1.order_serial",
                proWorkorder.getOrderSerial());

        query.like(StringUtils.isNotEmpty(proWorkorder.getCustomerProjectNo()), "t1.customer_project_no",
                proWorkorder.getCustomerProjectNo());

        query.like(StringUtils.isNotEmpty(proWorkorder.getWorkorderCode()), "t1.workorder_code",
                proWorkorder.getWorkorderCode());
        query.like(StringUtils.isNotEmpty(proWorkorder.getProductCode()), "t1.product_code",
                proWorkorder.getProductCode());
        query.like(StringUtils.isNotEmpty(proWorkorder.getProductName()), "t1.product_name",
                proWorkorder.getProductName());
        query.in(StringUtils.isNotEmpty(proWorkorder.getStatusArr()), "t1.status",
                proWorkorder.getStatusArr());
        query.in(StringUtils.isNotEmpty(proWorkorder.getStatusArr()), "t1.status",
                new String[]{WorkorderStatusEnum.PREPARE.getValue(), WorkorderStatusEnum.PUBLISHED.getValue()});
        query.gt("t1.quantity-t1.quantity_scheduled", 0);
        query.orderByDesc("request_date");
        List<ProWorkorder> list = proWorkorderService.selectListByQw(query);
        return getDataTable(list);
    }


    /**
     * 查询生产工单列表
     */
    @ApiOperation("查询工单打印数据")
    @GetMapping("/printInfo")
    public AjaxResult printInfo(ProWorkorderQuery proWorkorder) {
        List<ProWorkorderPrintTab> list = proWorkorderService.selectWorkorderPrintTab(proWorkorder);
        return AjaxResult.success(list);
    }

    @ApiOperation("查询生产工单列表，并联查指令与SIZE数据")
    @GetMapping("/listWithSizeAndDirective")
    public TableDataInfo<ProWorkorderVo> listWithSizeAndDirective(ProWorkorderQuery proWorkorder) {
        List<ProWorkorderVo> list = proWorkorderService.getFeedBackRecord(proWorkorder);
        return getDataTable(list);
    }

    @ApiOperation("工单关联属性查询")
    @GetMapping("/linkInfo")
    public AjaxResult<ProWorkorderVo> linkInfo(Long workorderId) {
        ProWorkorderVo rst = new ProWorkorderVo();
        ProWorkorder proWorkorder = proWorkorderService.selectWorkorderById(workorderId);
        BeanUtil.copyProperties(proWorkorder, rst);
        ProWorkOrderSoDirective directiveQuery = new ProWorkOrderSoDirective();
        directiveQuery.setWorkorderId(proWorkorder.getWorkorderId());
        List<ProWorkOrderSoDirective> directiveList = proWorkOrderSoDirectiveService.selectProWorkOrderSoDirectiveList(directiveQuery);
        ProWorkOrderSoSizeItem sizeQuery = new ProWorkOrderSoSizeItem();
        sizeQuery.setWorkorderId(proWorkorder.getWorkorderId());
        List<ProWorkOrderSoSizeItem> sizeList = proWorkOrderSoSizeItemService.selectProWorkOrderSoSizeItemList(sizeQuery);
        rst.setSaleDirectiveList(directiveList);
        rst.setSizeList(sizeList);
        if (directiveList.size() == 1) {
            if (directiveList.get(0).getPackNum() != null && rst.getUsagePackNum() == null) {
                rst.setUsagePackNum(directiveList.get(0).getPackNum().intValue());
            }
        }
        if (proWorkorder.getUsageEncasementNum() != null) {
            rst.setUsageEncasementNum(proWorkorder.getUsageEncasementNum());
        }
        if (proWorkorder.getUsagePackNum() != null) {
            rst.setUsagePackNum(proWorkorder.getUsagePackNum());
        }
        return AjaxResult.success(rst);
    }


    @Log(title = "用户管理", businessType = BusinessType.IMPORT)
    @PreAuthorize("@ss.hasPermi('system:user:import')")
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file) throws Exception {
        String message = proWorkorderService.importWorkOrder(file);
        return AjaxResult.success(message);
    }

    @GetMapping(value = "/getChildWorkorderCode/{workOrderCode}")
    public AjaxResult getChildOrderCode(@PathVariable("workOrderCode") String workorderCode) {
        if (workorderCode == null || "".equals(workorderCode)) {
            throw new RuntimeException("工单编码传递为空");
        }

        Integer i = proWorkorderService.countByParentCode(workorderCode);
        // 补料单生成编号
        Map<String, String> map = new HashMap<>();
        map.put("code", workorderCode + "-" + ((i == null ? 0 : i) + 1));
        return AjaxResult.success(map);
    }

    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) throws IOException {
        proWorkorderService.importTemplate(response);
    }

    /**
     * 获取生产工单详细信息
     */
    @GetMapping(value = "/{workorderId}")
    public AjaxResult getInfo(@PathVariable("workorderId") Long workorderId) {
        return AjaxResult.success(proWorkorderService.selectProWorkorderByWorkorderId(workorderId));
    }


    /**
     * 获取生产工单详细信息
     */
    @PostMapping(value = "/getQcCondition")
    public AjaxResult getQcCondition(@RequestBody ProWorkorder proWorkorder) {
        QueryWrapper<ProWorkorder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotEmpty(proWorkorder.getWorkorderCode()), "workorder_code", proWorkorder.getWorkorderCode());
        queryWrapper.eq(StringUtils.isNotEmpty(proWorkorder.getArrangeCode()), "arrange_code", proWorkorder.getArrangeCode());
        List<ProWorkorder> proWorkorders = proWorkorderService.selectListByQw(queryWrapper);

        ExceptionUtil.checkTrueThrowException(CollectionUtil.isEmpty(proWorkorders), MessageUtils.message("pro.workOrder.error.not.exist"));
        ProWorkorder proWorkorder1 = proWorkorders.get(0);
        List<ProWorkOrderProcessVo> proWorkOrderProcessList = proWorkOrderProcessMapper.selectProWorkOrderProcessByWorkOrderId(proWorkorder1.getWorkorderId());
        ProWorkorderVo proWorkorderVo = proWorkorder1.deepCopyObj(ProWorkorderVo.class);
        proWorkorderVo.setProcessList(proWorkOrderProcessList);
        return AjaxResult.success(proWorkorderVo);
    }


    /**
     * 新增生产工单
     */

    @ApiOperation("生产工单新增")
    @PreAuthorize("@ss.hasPermi('mes:pro:workorder:add')")
    @Log(title = "生产工单", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody ProWorkorderVo proWorkorderVo) {
        ProWorkorder proWorkorder = proWorkorderVo.deepCopyObj(ProWorkorder.class);
        ExceptionUtil.checkTrueThrowException(!proWorkorderService.checkWorkorderIsExsit(proWorkorder), MessageUtils.message("pro.workOrder.error.workOrderNo.exist"));

        ProWorkorder proWorkorderNew = proWorkorderService.insertObj(proWorkorder, proWorkorderVo);
        return AjaxResult.success(proWorkorderNew.getWorkorderId());
    }


    /**
     * 修改生产工单
     */
    @PreAuthorize("@ss.hasPermi('mes:pro:workorder:edit')")
    @Log(title = "生产工单", businessType = BusinessType.UPDATE)
    @PutMapping("/close")
    public AjaxResult close(@RequestBody List<ProWorkorderVo> proWorkorderVos) {
        for (ProWorkorderVo proWorkorderVo : proWorkorderVos) {
            proWorkorderService.updateObject(proWorkorderVo);
        }
        return AjaxResult.success();
    }

    @PreAuthorize("@ss.hasPermi('mes:pro:workorder:add')")
    @Log(title = "生产补单工单", businessType = BusinessType.INSERT)
    @PostMapping("/addComplements")
    public AjaxResult addComplements(@RequestBody ProWorkorderVo proWorkorderVo) {
        proWorkorderService.addComplements(proWorkorderVo);
        return AjaxResult.success();
    }

    /**
     * 修改生产工单
     */
    @ApiOperation("生产工单修改")
    @PreAuthorize("@ss.hasPermi('mes:pro:workorder:edit')")
    @Log(title = "生产工单", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody ProWorkorderVo proWorkorderVo) {
        int ret = proWorkorderService.updateObject(proWorkorderVo);

        return toAjax(ret);
    }

    /**
     * 修改生产工单
     */
    @ApiOperation("生产工单修改生产版本以及工艺路线")
    @PreAuthorize("@ss.hasPermi('mes:pro:workorder:edit')")
    @Log(title = "生产工单", businessType = BusinessType.UPDATE)
    @PutMapping("/updateWorkProcess")
    public AjaxResult updateWorkProcess(@RequestBody ProWorkorderVo proWorkorderVo) {
        int ret = proWorkorderService.updateWorkProcess(proWorkorderVo);

        return toAjax(ret);
    }




    /**
     * 删除生产工单
     */
    @PreAuthorize("@ss.hasPermi('mes:pro:workorder:remove')")
    @Log(title = "生产工单", businessType = BusinessType.DELETE)
    @DeleteMapping("/{workorderIds}")
    public AjaxResult remove(@PathVariable Long[] workorderIds) {
        for (Long id : workorderIds) {
            ProWorkorderVo workorder = proWorkorderService.selectProWorkorderByWorkorderId(id);
            if (!UserConstants.ORDER_STATUS_PREPARE.equals(workorder.getStatus())) {
                return AjaxResult.error(MessageUtils.message("pro.workOrder.error.limit.delete"));
            }
            proWorkorderBomService.deleteProWorkorderBomByWorkorderId(id);

        }
        return toAjax(proWorkorderService.deleteProWorkorderByWorkorderIds(workorderIds));
    }


    /**
     * 获取当前工单的物料需求清单
     */
    @PreAuthorize("@ss.hasPermi('mes:pro:workorder:list')")
    @GetMapping("/listItems")
    public TableDataInfo listItemss(ProWorkorder proWorkorder) {
        List<MdProductBom> result = new ArrayList<MdProductBom>();
        ProWorkorderBomm param = new ProWorkorderBomm();
        param.setWorkorderId(proWorkorder.getWorkorderId());
        List<ProWorkorderBomm> boms = proWorkorderBomService.selectProWorkorderBomList(param);
        if (!CollectionUtils.isEmpty(boms)) {
            for (ProWorkorderBomm bom : boms
            ) {
                MdProductBom theBom = new MdProductBom();
                theBom.setBomItemId(bom.getItemId());
                result.addAll(getBoms(theBom, bom.getQuantity(), 0));
            }
        }
        return getDataTable(result);
    }

    private List<MdProductBom> getBoms(MdProductBom item, BigDecimal quantity, int count) {
        MdProductBom param = new MdProductBom();
        List<MdProductBom> results = new ArrayList<MdProductBom>();
        if (count > 20) {
            return results;
        }
        param.setItemId(item.getBomItemId());
        List<MdProductBom> boms = mdProductBomService.selectMdProductBomList(param);
        if (CollUtil.isNotEmpty(boms)) {
            //最多20层依赖
            count++;
            for (MdProductBom bomItem : boms) {
                bomItem.setQuantity(quantity.multiply(bomItem.getQuantity()));
                results.addAll(getBoms(bomItem, bomItem.getQuantity(), count));
            }
        } else {
            results.add(item);
        }
        return results;
    }


    /**
     * 完成工单
     *
     * @param workorderId
     * @return
     */
    @PreAuthorize("@ss.hasPermi('mes:pro:workorder:edit')")
    @Log(title = "生产工单", businessType = BusinessType.UPDATE)
    @Transactional
    @PutMapping("/{workorderId}")
    public AjaxResult dofinish(@PathVariable Long workorderId) {
        ProWorkorderVo proWorkorderVo = proWorkorderService.selectProWorkorderByWorkorderId(workorderId);
        ProWorkorder workorder = proWorkorderVo.deepCopyObj(ProWorkorder.class);
        //将此工单下所有的生产任务状态设置为已完成
        ProTask param = new ProTask();
        param.setArrangeCode(workorder.getArrangeCode());
        List<ProTask> tasks = proTaskService.selectProTaskList(param);
        if (!CollectionUtils.isEmpty(tasks)) {
            for (ProTask task : tasks) {
                task.setStatus(UserConstants.ORDER_STATUS_FINISHED);
                proTaskService.updateProTask(task);
            }
        }

        workorder.setStatus(UserConstants.ORDER_STATUS_FINISHED); //更新工单的状态
        proWorkorderService.updateProWorkorder(workorder);
        return AjaxResult.success();
    }

    /**
     * 生产工单工装量具齐套检查
     */
    @PostMapping(value = "/checkToolNum")
    public void checkToolNum(@RequestBody ProWorkorderVo proWorkorderVo) {
        proWorkorderService.checkToolNum(proWorkorderVo.getWorkorderIds());
    }

    /**
     * 生产工单将草稿状态改为已确认
     */
    @GetMapping(value = "/setStatus/{workorderId}")
    public void setStaus(@PathVariable("workorderId") Long workorderId) {
        ProWorkorder workorder = proWorkorderService.selectWorkorderById(workorderId);
        proWorkorderService.updateWorkorderState(workorder, WorkorderStatusEnum.PUBLISHED);
    }

    @PostMapping(value = "/proofMakeProduction")
    public AjaxResult proofMakeProduction(@RequestBody WorkorderProofMakeProduction production) {
        proWorkorderService.proofMakeProduction(production);
        return AjaxResult.success();
    }

    /**
     * 导出生产工单列表
     */
    @PreAuthorize("@ss.hasPermi('mes:pro:workorder:export')")
    @Log(title = "生产工单", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, ProWorkorderQuery proWorkorder) throws IOException {
        List<ProWorkorder> list = proWorkorderService.selectProWorkorderList(proWorkorder);
        List<ProWorkorderExcelExport> exportList = BeanUtil.copyToList(list, ProWorkorderExcelExport.class);
        ExcelWriter.write(response,ProWorkorderExcelExport.class,exportList);
    }


    /**
     * 同步ERP数据
     */
    @PreAuthorize("@ss.hasPermi('mes:pro:workorder:sync')")
    @Log(title = "工单同步", businessType = BusinessType.SYNC_DATA)
    @PostMapping("/syncData")
    public AjaxResult syncData() {
        proWorkorderService.syncErpData();
        return AjaxResult.success();
    }
}
