package cn.ezhizao.project.business.controller;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.ezhizao.framework.redis.RedisCache;
import cn.ezhizao.project.business.domain.*;
import cn.ezhizao.project.business.service.*;
import org.aspectj.weaver.loadtime.Aj;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import cn.ezhizao.framework.aspectj.lang.annotation.Log;
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.common.utils.poi.ExcelUtil;
import cn.ezhizao.framework.web.page.TableDataInfo;

/**
 * 外协单主
带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子Controller
 *
 * @author 庄德政
 * date    2024-04-26
 */
@RestController
@RequestMapping("/business/outsource")
public class BizOutsourcedOrderController extends BaseController
{
    @Resource
    private IBizOutsourcedOrderService bizOutsourcedOrderService;
    @Resource
    private IBizOutsourcedOrderDetailService bizOutsourcedOrderDetailService;
    @Resource
    private IBizOutsourcedOrderDetailProcessService bizOutsourcedOrderDetailProcessService;
    @Resource
    private IBizReturnReceiptService bizReturnReceiptService;
    @Resource
    private IBizReturnReceiptDetailService bizReturnReceiptDetailService;
    @Resource
    private IBizCarrierService bizCarrierService;
    @Resource
    private IBizDayworkCarrierService bizDayworkCarrierService;
    @Resource
    private IBizFurnaceNoInfoService bizFurnaceNoInfoService;
    @Resource
    private IBizCarrierCategoryService bizCarrierCategoryService;
    @Resource
private IBizDayworkService bizDayworkService;
    @Resource
    private IBizDayworkItemService bizDayworkItemService;
    @Resource
    HttpServletRequest request;
    /**
     * 查询外协单主
带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子列表
     */
    @PreAuthorize("@ss.hasPermi('business:outsource:list')")
    @Log(title = "外协发出单查询", businessType = BusinessType.SELECT)
    @GetMapping("/list")
    public TableDataInfo list(BizOutsourcedOrder bizOutsourcedOrder) throws NoSuchFieldException, IllegalAccessException
    {
        final String supplierId = request.getHeader("tenantId");
        bizOutsourcedOrder.setSupplierId(Long.parseLong(supplierId));
        startPage();
        List<BizOutsourcedOrder> list = bizOutsourcedOrderService.getList(bizOutsourcedOrder);
        return getDataTable(list);
    }
    /**
     * 导出外协单主
带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子列表
     */
    @PreAuthorize("@ss.hasPermi('business:outsource:export')")
    @Log(title = "外协发出单导出", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, BizOutsourcedOrder bizOutsourcedOrder) throws NoSuchFieldException, IllegalAccessException
    {
        setTenantId(bizOutsourcedOrder);
        List<BizOutsourcedOrder> list = bizOutsourcedOrderService.getList(bizOutsourcedOrder);
        ExcelUtil<BizOutsourcedOrder> util = new ExcelUtil<>(BizOutsourcedOrder.class);
        util.exportExcel(response, list, "外协单主带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子数据");
    }

    /**
     * 获取外协单主 带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子详细信息
     */
    @PreAuthorize("@ss.hasPermi('business:outsource:query')")
    @Log(title = "外协单明细查询", businessType = BusinessType.SELECT)
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id)
    {
        // 根据 id 获取到外协订单
        BizOutsourcedOrder outsourcedOrder = bizOutsourcedOrderService.getById(id);

        // 根据外协订单id，获取到该外协订单的所有明细
        List<BizOutsourcedOrderDetail> outsourcedOrderDetails = bizOutsourcedOrderDetailService.query()
                .eq("master_id", id)
                .list();
        List<BizFurnaceNoInfo> furnaceNoInfos = bizFurnaceNoInfoService.query().in("daywork_id", outsourcedOrderDetails.isEmpty() ? Collections.singletonList(0L) : outsourcedOrderDetails.stream().map(BizOutsourcedOrderDetail::getDayworkId).collect(Collectors.toList())).list();

        // 将得到的外协明细的id，组合成一个集合，用于查询这个订单下的，所有外协出来的工序，
        // 这里得到的工序清单，是混合的，并没有根据各自对应的明细，进行分组，仅仅是获取全部，为后续分组做准备
        List<Long> detailIds = outsourcedOrderDetails.stream()
                .map(BizOutsourcedOrderDetail::getId)
                .collect(Collectors.toList());
        List<BizOutsourcedOrderDetailProcess> detailProcesses = bizOutsourcedOrderDetailProcessService.query()
                .in("detail_id", detailIds)
                .orderByAsc(Arrays.asList("detail_id", "process_step_number"))
                .list();

        // 遍历明细，将对应的工序，与订单明细进行匹配
        outsourcedOrderDetails.forEach(item -> {
            // 根据明细的id，获取到该明细对应的外协工序，并将得到的工序，组成中文逗号分割的字符串
            String processNames = detailProcesses.stream()
                    .filter(dp -> dp.getDetailId().equals(item.getId()))
                    .sorted(Comparator.comparing((BizOutsourcedOrderDetailProcess::getProcessStepNumber)))
                    .map(BizOutsourcedOrderDetailProcess::getProcessAlias)
                    .collect(Collectors.joining("，"));
            String furnaceNumber = furnaceNoInfos.stream().filter(f -> f.getDayworkId().equals(item.getDayworkId())).map(BizFurnaceNoInfo::getFurnaceNumber).collect(Collectors.joining("，"));

            item.setProcessNames(processNames);
            item.setFurnaceNumber(furnaceNumber);
        });
        outsourcedOrderDetails.forEach(detail -> {
            // 将字符串拆分转为对象
            List<BizCarrier> carriers = new ArrayList<>();
            // 因为需要显示箱号，所以需要拆分出code重新拼接到NewCarrier
            List<String> codeList = new ArrayList<>();
            // 为了减少前段的逻辑，所以需要先将拆分后的id也拼接起来
            List<Long> carrierIds = new ArrayList<>();

            //使用 StringTokenizer 来分割字符串
            StringTokenizer tokenizer = new StringTokenizer(detail.getNewCarrier(), ",");
            while (tokenizer.hasMoreTokens()) {
                String token = tokenizer.nextToken();
                // 检查当前 token 是否包含 "|" 字符 如果没有表示不是新箱，则跳过当前 token
                if (token.contains("|")) {
                    String[] idCode = token.split("\\|"); // 安全地分割 token
                    if (idCode.length == 2) {
                        codeList.add(idCode[1]);
                        carrierIds.add(Long.parseLong(idCode[0]));
                        BizCarrier bizCarrier = new BizCarrier();
                        bizCarrier.setId(Long.parseLong(idCode[0]));
                        bizCarrier.setCode(idCode[1]);
                        carriers.add(bizCarrier);
                    }
                }
            }
            if(codeList.size()>0){
                detail.setNewCarrier(String.join(",", codeList));
            }

        });

        // 将外协明细赋值给外协订单
        outsourcedOrder.setDetails(outsourcedOrderDetails);

        return success(outsourcedOrder);
    }
    @Log(title = "外协查询箱号", businessType = BusinessType.SELECT)
    @GetMapping(value = "/carrierForOutsource")
    public TableDataInfo carrierForOutsource(BizCarrier carrier) {

        carrier.setNotInUse(1);
//        carrier.setIsAllowMore(0);
        List<BizCarrier> list = bizCarrierService.getListFromOutsource(carrier);
        return getDataTable(list);
    }
    @Log(title = "外协保存箱号", businessType = BusinessType.EXPORT)
    @PostMapping("/saveCarriers")
    public AjaxResult saveCarriers(@RequestBody BizOutsourcedOrderDetail bizOutsourcedOrderDetail) {
        // 保存时校验一箱多批。
        BizOutsourcedOrderDetail detail = bizOutsourcedOrderDetailService.getById(bizOutsourcedOrderDetail.getDetailId());
        detail.setNewCarrierCount(bizOutsourcedOrderDetail.getCarrierIds().size());
        List<BizCarrier> carriers = bizCarrierService.query().in("id", bizOutsourcedOrderDetail.getCarrierIds()).list();
        // 获取箱类型盘点是否有一箱多批的箱子
        List<BizCarrierCategory> bizCarrierCategories = bizCarrierCategoryService.query().in( "id", carriers.isEmpty() ? Collections.singletonList(0L): carriers.stream().map(BizCarrier::getCategoryId).collect(Collectors.toList())).list();
        if (bizCarrierCategories.stream().anyMatch(v -> v.getIsAllowMore().equals(1)) && bizCarrierCategories.stream().anyMatch(v -> v.getIsAllowMore().equals(0))) {
            return AjaxResult.error("周转箱既有铁箱又有蓝箱，请选择正确载具。");
        }

        // 判断箱子类型，假设是可以装多批，且箱子有多个 报错
        if (bizCarrierCategories.stream().allMatch(v -> v.getIsAllowMore().equals(1)) && carriers.size() > 1) {
            return AjaxResult.error("该批次关联多个铁箱，请选择正确的载具。");
        }
        // 获取这些箱对应的所有批次
        List<BizDayworkCarrier> carrierDaywork = bizDayworkCarrierService.query().eq("is_changed", 0).eq("process_inspection_id", 0L).in("carrier_id",carriers.isEmpty() ? Collections.singletonList(0L) : carriers.stream().map(BizCarrier::getId).collect(Collectors.toList())).list();
        // 获取所有批次的报工状态
        List<BizDaywork> bizDayworks = bizDayworkService.query().in("id",carrierDaywork.isEmpty() ? Collections.singletonList(0L) : carrierDaywork.stream().map(BizDayworkCarrier::getDayworkId).collect(Collectors.toList())).list();
        List<BizDayworkItem> bizDayworkItems = bizDayworkItemService.query().in("daywork_id",bizDayworks.isEmpty() ? Collections.singletonList(0L) : bizDayworks.stream().map(BizDaywork::getId).collect(Collectors.toList())).list();
        // 判断箱子类型，假设是不可装多批则只能有一个批次，假设有多个 报错
        if (bizCarrierCategories.stream().allMatch(v -> v.getIsAllowMore().equals(0)) && bizDayworks.size() > 1) {
            return AjaxResult.error("存在蓝箱关联多个批次，请选择正确箱号");
        }
        // 获取批次绑定的外协单工序和批号
//        BizOutsourcedOrder order = bizOutsourcedOrderService.getById(bizOutsourcedOrderDetail.getMasterId());
        List<BizOutsourcedOrderDetail> allDetail = bizOutsourcedOrderDetailService.query().eq("master_id", bizOutsourcedOrderDetail.getMasterId()).eq("daywork_id", bizDayworks.stream().map(BizDaywork::getId).collect(Collectors.toList())).list();
        List<BizOutsourcedOrderDetailProcess> processes = bizOutsourcedOrderDetailProcessService.query().eq("master_id", bizOutsourcedOrderDetail.getMasterId()).list();
        allDetail.forEach(l -> {
            l.setProcesses(processes.stream().filter(v -> v.getDetailId().equals(l.getId())).collect(Collectors.toList()));
        });
        List<BizReturnReceiptDetail> bizReturnReceiptDetails = bizReturnReceiptDetailService.query().in("outsource_detail_id", allDetail.stream().map(BizOutsourcedOrderDetail::getId).collect(Collectors.toList())).list();
        if (bizDayworks.stream().anyMatch(t -> allDetail.stream().anyMatch(v -> v.getDayworkId().equals(t.getId())))) {
            return error("当前载具绑定批次不在当前外协单中,请重新选择");
        }
        if (bizReturnReceiptDetails.stream().anyMatch(v -> bizDayworks.stream().anyMatch(t -> t.getId().equals(v.getDayworkId())))) {
            return error("当前载具绑定批次已收回,请重新选择");
        }
        if(allDetail.stream().anyMatch(v -> !allDetail.get(0).getProductionPlanDetailId().equals(v.getProductionPlanDetailId()) || allDetail.get(0).getProcesses().stream().anyMatch(t -> v.getProcesses().stream().noneMatch(e -> e.getTechnologicalProcessDetailId().equals(t.getTechnologicalProcessDetailId()))))) {
            return error("当前载具已绑定其他计划单/工序,请重新选择");
        }

        detail.setNewCarrier(carriers.stream().map(v -> v.getId() + "|" + v.getCode()).collect(Collectors.joining(",")));
        detail.setNewCarrierName(carriers.stream().map(BizCarrier::getCode).collect(Collectors.joining(",")));
        bizOutsourcedOrderDetailService.updateById(detail);
        List<BizDayworkCarrier> oldCarriers = bizDayworkCarrierService.query().eq("daywork_id", bizOutsourcedOrderDetail.getDayworkId()).list();
        oldCarriers.forEach(l -> {
            l.setIsChanged(1);
        });
        bizDayworkCarrierService.updateBatchById(oldCarriers);
        List<BizDayworkCarrier> newCarriers = new ArrayList<>();
        carriers.forEach(l -> {
            BizDayworkCarrier item = new BizDayworkCarrier();
            item.setCarrierId(l.getId());
            item.setCarrierCode(l.getCode());
            item.setLotId(bizOutsourcedOrderDetail.getLotId());
            item.setDayworkId(bizOutsourcedOrderDetail.getDayworkId());
            item.setProductId(bizOutsourcedOrderDetail.getProductId());
            newCarriers.add(item);
        });
        bizDayworkCarrierService.saveBatch(newCarriers);
        return success();
    }
}
