package com.ximai.mes.pro.service.impl.task;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ximai.common.constant.DataConstans;
import com.ximai.common.utils.MessageUtils;
import com.ximai.common.utils.SecurityUtils;
import com.ximai.common.utils.data.DataUtil;
import com.ximai.common.utils.data.ExceptionUtil;
import com.ximai.common.utils.data.StringUtils;
import com.ximai.mes.constant.TaskStatusEnum;
import com.ximai.mes.constant.TaskWorkunitStatusEnum;
import com.ximai.mes.constant.WorkorderStatusEnum;
import com.ximai.mes.pro.domain.ProFeedback;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkOrderProcess;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkorder;
import com.ximai.mes.pro.domain.task.ProTask;
import com.ximai.mes.pro.domain.task.ProTaskAssistProcess;
import com.ximai.mes.pro.domain.task.ProTaskWorkunit;
import com.ximai.mes.pro.domain.vo.ProTaskVo;
import com.ximai.mes.pro.domain.vo.ProWorkOrderProcessVo;
import com.ximai.mes.pro.mapper.ProFeedbackMapper;
import com.ximai.mes.pro.mapper.ProProcessMapper;
import com.ximai.mes.pro.mapper.proWorkOrder.ProWorkOrderProcessMapper;
import com.ximai.mes.pro.mapper.proWorkOrder.ProWorkorderMapper;
import com.ximai.mes.pro.mapper.task.ProTaskAssistProcessMapper;
import com.ximai.mes.pro.mapper.task.ProTaskMapper;
import com.ximai.mes.pro.mapper.task.ProTaskWorkunitMapper;
import com.ximai.mes.pro.service.IProFeedbackService;
import com.ximai.mes.pro.service.IProStartWorkService;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkOrderProcessService;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkorderService;
import com.ximai.mes.pro.service.task.IProFdQrcodePrintRecordService;
import com.ximai.mes.pro.service.task.IProTaskAssistProcessService;
import com.ximai.mes.pro.service.task.IProTaskService;
import com.ximai.mes.pro.service.task.IProTaskWorkunitService;
import com.ximai.system.mapper.SysUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static com.ximai.mes.constant.TaskWorkunitStatusEnum.BEGINNING;
import static com.ximai.mes.constant.TaskWorkunitStatusEnum.FINISHED;

/**
 * 工序任务外协关系Service业务层处理
 *
 * @author generator
 * @date 2024-03-29
 */
@Slf4j
@Service
public class ProTaskAssistProcessServiceImpl implements IProTaskAssistProcessService {

    @Autowired
    private ProTaskAssistProcessMapper proTaskAssistProcessMapper;

    @Resource
    private ProFeedbackMapper proFeedbackMapper;
    @Resource
    private ProWorkorderMapper proWorkorderMapper;

    @Resource
    private ProWorkOrderProcessMapper proWorkOrderProcessMapper;
    @Autowired
    private IProWorkorderService proWorkorderService;

    @Autowired
    private IProTaskWorkunitService proTaskWorkunitService;


    @Autowired
    private IProFdQrcodePrintRecordService proFdQrcodePrintRecordService;
    @Resource
    private ProTaskWorkunitMapper proTaskWorkunitMapper;

    @Autowired
    private IProFeedbackService proFeedbackService;

    @Autowired
    private IProStartWorkService proStartWorkService;
    @Autowired
    private IProTaskService proTaskService;
    @Resource
    private ProTaskMapper proTaskMapper;

    @Autowired
    private IProWorkOrderProcessService proWorkOrderProcessService;

    @Resource
    private ProProcessMapper proProcessMapper;
    @Resource
    private SysUserMapper sysUserMapper;

    /**
     * 查询工序任务外协关系
     *
     * @param id 工序任务外协关系主键
     * @return 工序任务外协关系
     */
    @Override
    public ProTaskAssistProcess selectProTaskAssistProcessById(Long id) {
        return proTaskAssistProcessMapper.selectProTaskAssistProcessById(id);
    }

    @Override
    public Boolean queryAssistProcessIsCompleted(String code) {
        return proTaskAssistProcessMapper.selectTaskAssistProcessByTwCode(code) != null;
    }

    /**
     * 查询工序任务外协关系列表
     *
     * @param proTaskAssistProcesses 工序任务外协关系
     * @return 工序任务外协关系
     */
    @Override
    public List<ProTaskAssistProcess> listUnreportedFeedback(ProTaskAssistProcess proTaskAssistProcesses) {
        return this.selectListByObj(proTaskAssistProcesses).stream().filter(x -> x.getAssistProcessCode() != null && this.queryAssistProcessIsCompleted(x.getAssistProcessCode())).collect(Collectors.toList());
    }

    @Override
    public List<ProTaskAssistProcess> getAssistProcesslist(ProTaskAssistProcess proTaskAssistProcess) {
        QueryWrapper<ProTaskAssistProcess> qw = new QueryWrapper<>();
        if (proTaskAssistProcess.getAllowProduce() != null && proTaskAssistProcess.getAllowProduce() == 1) {
            qw.gt("pt.quantity_wait", 0).or().eq("ptap.close_Type", 0);
        }
        qw.eq(StringUtils.isNotEmpty(proTaskAssistProcess.getWorkorderCode()), "pw.workorder_code", proTaskAssistProcess.getWorkorderCode());

        qw.eq(StringUtils.isNotEmpty(proTaskAssistProcess.getAssistProcessCode()), "ptap.assist_process_code", proTaskAssistProcess.getAssistProcessCode());
        qw.eq(StringUtils.isNotEmpty(proTaskAssistProcess.getAssistProcessItemCode()), "ptap.assist_process_item_code", proTaskAssistProcess.getAssistProcessItemCode());
        qw.orderByAsc("ptap.schedule_end_date");
        List<ProTaskAssistProcess> assistProcesslist = proTaskAssistProcessMapper.getAssistProcesslist(qw);
        for (ProTaskAssistProcess assistProcess : assistProcesslist) {
            Long taskWorkunitId = assistProcess.getTaskWorkunitId();
            Long sum = proFeedbackMapper.selectListByQw(new QueryWrapper<ProFeedback>().eq("task_workunit_id", taskWorkunitId)).stream().filter(x -> x.getQuantityFeedback() != null).collect(Collectors.summarizingLong(y -> y.getQuantityFeedback().longValue())).getSum();
            assistProcess.setQuantityFeedback(sum);
        }
        return assistProcesslist;
    }

    /**
     * 查询工序任务外协关系列表
     *
     * @param proTaskAssistProcesses 工序任务外协关系
     * @return 工序任务外协关系
     */
    @Override
    public List<ProTaskAssistProcess> selectListByObj(ProTaskAssistProcess proTaskAssistProcesses) {
        QueryWrapper<ProTaskAssistProcess> proTaskAssistProcessQueryWrapper = new QueryWrapper<>();
        proTaskAssistProcessQueryWrapper.eq(StringUtils.isNotEmpty(proTaskAssistProcesses.getAssistProcessCode()), "assist_process_code", proTaskAssistProcesses.getAssistProcessCode());
        proTaskAssistProcessQueryWrapper.eq(StringUtils.isNotEmpty(proTaskAssistProcesses.getAssistProcessItemCode()), "assist_process_item_code", proTaskAssistProcesses.getAssistProcessItemCode());
        proTaskAssistProcessQueryWrapper.eq(StringUtils.isNotEmpty(proTaskAssistProcesses.getProcessId()), "process_id", proTaskAssistProcesses.getProcessId());
        proTaskAssistProcessQueryWrapper.eq(StringUtils.isNotEmpty(proTaskAssistProcesses.getTaskWorkunitId()), "task_workunit_id", proTaskAssistProcesses.getTaskWorkunitId());

        proTaskAssistProcessQueryWrapper.eq(StringUtils.isNotEmpty(proTaskAssistProcesses.getProcessName()), "process_name", proTaskAssistProcesses.getProcessName());
        proTaskAssistProcessQueryWrapper.eq(StringUtils.isNotEmpty(proTaskAssistProcesses.getWorkorderId()), "workorder_id", proTaskAssistProcesses.getWorkorderId());
        proTaskAssistProcessQueryWrapper.eq(StringUtils.isNotEmpty(proTaskAssistProcesses.getWorkorderCode()), "workorder_code", proTaskAssistProcesses.getWorkorderCode());
        List<ProTaskAssistProcess> proTaskAssistProcessList = this.selectListByQw(proTaskAssistProcessQueryWrapper);
        for (ProTaskAssistProcess proTaskAssistProcess : proTaskAssistProcessList) {
            Long taskWorkunitId = proTaskAssistProcess.getTaskWorkunitId();
            Long sum = proFeedbackMapper.selectListByQw(new QueryWrapper<ProFeedback>().eq("task_workunit_id", taskWorkunitId)).stream().filter(x -> x.getQuantityFeedback() != null).collect(Collectors.summarizingLong(y -> y.getQuantityFeedback().longValue())).getSum();
            proTaskAssistProcess.setQuantityFeedback(sum);
        }
        return proTaskAssistProcessList;
    }

    @Override
    public List<ProTaskAssistProcess> selectListByQw(QueryWrapper<ProTaskAssistProcess> qw) {
        if (!qw.getSqlSelect().contains("delete")) {
            qw.eq("delete_state", DataConstans.MARK_NOMAL);
        }
        return proTaskAssistProcessMapper.selectListByQw(qw);
    }


    @Override
    public ProTaskAssistProcess selectBaseByObj(ProTaskAssistProcess proTaskAssistProcesses) {
        List<ProTaskAssistProcess> proTaskAssistProcessList = this.selectListByObj(proTaskAssistProcesses);
        return CollectionUtil.isEmpty(proTaskAssistProcessList) ? null : proTaskAssistProcessList.get(0);
    }


    /**
     * 新增工序任务外协关系
     *
     * @param proTaskAssistProcess 工序任务外协关系
     * @return 结果
     */
    @Override
    public int insertProTaskAssistProcess(ProTaskAssistProcess proTaskAssistProcess) {
        proTaskAssistProcess.createAction();
        return proTaskAssistProcessMapper.insertProTaskAssistprocess(proTaskAssistProcess);
    }


    /**
     * 修改工序任务外协关系
     *
     * @param proTaskAssistProcess 工序任务外协关系
     * @return 结果
     */
    @Override
    public int updateProTaskAssistprocess(ProTaskAssistProcess proTaskAssistProcess) {
        proTaskAssistProcess.updateAction();
        return proTaskAssistProcessMapper.updateProTaskAssistProcess(proTaskAssistProcess);
    }

    /**
     * 修改工序任务外协关系
     *
     * @param updateAssistProcess 工序任务外协关系
     * @return 结果
     */
    @Transactional
    @Override
    public int updateObj(ProTaskAssistProcess updateAssistProcess) {
        return 1;
    }


    /**
     * 修改工序任务外协关系
     *
     * @param proTaskAssistprocess 工序任务外协关系
     * @return 结果
     */
    @Override
    public int updateProTaskAssistProcess(ProTaskAssistProcess proTaskAssistprocess) {
        proTaskAssistprocess.updateAction();
        return proTaskAssistProcessMapper.updateProTaskAssistProcess(proTaskAssistprocess);
    }


    /**
     * 批量删除工序任务外协关系
     *
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteObj(ProTaskAssistProcess updateAssistProcess) {
        return 1;
    }

    /**
     * 批量删除工序任务外协关系
     *
     * @param ids 需要删除的工序任务外协关系主键
     * @return 结果
     */
    @Override
    public int deleteProTaskAssistProcessByIds(Long[] ids) {
        return proTaskAssistProcessMapper.deleteProTaskAssistProcessByIds(ids);
    }

    /**
     * 删除工序任务外协关系信息
     *
     * @param id 工序任务外协关系主键
     * @return 结果
     */
    @Override
    public int deleteProTaskAssistProcessById(Long id) {
        return proTaskAssistProcessMapper.deleteProTaskAssistProcessById(id);
    }


    // oper_no
    @Transactional
    @Override
    public int feedBack(ProFeedback feedback) {
        Long taskWorkunitId = feedback.getTaskWorkunitId();
        ProTaskWorkunit taskWorkunit = proTaskWorkunitService.selectProTaskWorkunitByTaskWorkunitId(taskWorkunitId);
        ProWorkorder workorder = proWorkorderMapper.selectWorkorderById(feedback.getWorkorderId());
        ExceptionUtil.checkTrueThrowException(taskWorkunit == null, MessageUtils.message("pro.schedule.data.not.exists"));
        ExceptionUtil.checkTrueThrowException(!taskWorkunit.getStatus().equals(TaskStatusEnum.BEGINNING.getStatus()), MessageUtils.message("pro.feedback.error.before.start"));
        feedback.initValue(workorder,taskWorkunit);
        Double feedbackSum = proFeedbackService.selectQuantityQualifySum(new ProFeedback(null, null, null, taskWorkunitId));
        double taskQuantityDouble = taskWorkunit.getQuantity().doubleValue();
        double canBeWaitQuantity = taskQuantityDouble - feedbackSum;
        ExceptionUtil.checkTrueThrowException(canBeWaitQuantity <= 0, MessageUtils.message("pro.feedback.error.min.quantity"));
        BigDecimal quantityQualify = feedback.getQuantityQualify();
        BigDecimal quantityUnQualify = feedback.getQuantityUnqualify();
        BigDecimal quantityFeedback = quantityQualify.add(quantityUnQualify);
        double quantityFeedbackDouble = quantityFeedback.doubleValue();
        ExceptionUtil.checkTrueThrowException(quantityFeedbackDouble > canBeWaitQuantity, MessageUtils.message("pro.feedback.error.quantity.lack"));

        ProTask task = proTaskService.selectBaseById(taskWorkunit.getTaskId());
        BigDecimal taskQuantityWait = task.getQuantityWait();
        ExceptionUtil.checkTrueThrowException(quantityFeedbackDouble > taskQuantityWait.longValue()
                || quantityFeedbackDouble > taskQuantityDouble, MessageUtils.message("pro.feedback.error.quantity.lack"));

        BigDecimal quantityWait = taskQuantityWait.subtract(quantityFeedback);
        task.setQuantityWait(quantityWait);
        task.setQuantityQualify(task.getQuantityQualify().add(quantityQualify));
        task.setQuantityUnqualify(task.getQuantityUnqualify().add(quantityUnQualify));
        task.setQuantityProduced(task.getQuantityProduced().add(quantityFeedback));

        taskWorkunit.setQuantityQualify(taskWorkunit.getQuantityQualify().add(quantityQualify));
        taskWorkunit.setQuantityUnqualify(taskWorkunit.getQuantityUnqualify().add(quantityUnQualify));
        taskWorkunit.setQuantityProduced(taskWorkunit.getQuantityProduced().add(quantityFeedback));

        if (feedback.getCloseType() == 1 || taskWorkunit.getQuantity().compareTo(taskWorkunit.getQuantityProduced()) <= 0) {
            taskWorkunit.setStatus(TaskWorkunitStatusEnum.FINISHED.getStatus());
            taskWorkunit.setActualEndDate(Calendar.getInstance().getTime());
        }

        //按派工表保存报工记录
        feedback.setFeedbackType("OUTSOURCE");
        feedback.setNickName(sysUserMapper.selectUserById(SecurityUtils.getUserId()).getNickName());
        proFeedbackService.insertProFeedback(feedback);

        //查询关联下道工序
        ProTask nextTask = proTaskService.getNextTaskByTaskId(feedback.getTaskId());
        if (nextTask != null) {
            nextTask.setQuantityWait(DataUtil.getNormalData(nextTask.getQuantityWait()));

            // 下道任务待加工数累加合格数量
            if (quantityQualify.doubleValue() > 0) {
                nextTask.setQuantityWait(nextTask.getQuantityWait().add(quantityQualify));
            }

            List<ProTaskWorkunit> proTaskWorkunits = proTaskWorkunitMapper.selectListByQw(new QueryWrapper<ProTaskWorkunit>().eq("task_id", nextTask.getTaskId()));
            proTaskWorkunits.stream().filter(x -> Objects.equals(x.getStatus(), FINISHED.getStatus())).forEach(x -> {
                x.setStatus(BEGINNING.getStatus());
                proTaskWorkunitService.updateProTaskWorkunit(x);
            });
            proTaskService.updateProTask(nextTask);
        }
        proTaskService.updateProTask(task);
        proTaskWorkunitService.updateProTaskWorkunit(taskWorkunit);

        // 末道工序：与普通报工 doFeedBack 一致，回写工单并触发 ERP 完工入库（reportUpdateProWorkorder，开关 erp.finish.stockin.create.enable）
        if (nextTask == null && quantityQualify.compareTo(BigDecimal.ZERO) > 0) {
            if (workorder != null) {
                proWorkorderService.reportUpdateProWorkorder(workorder, quantityQualify, quantityUnQualify);
                proFeedbackService.markSapPushedAfterAuto(feedback.getRecordId(),
                        "erp.finish.stockin.create.enable", com.ximai.mes.constant.FeedbackSapPushConst.TYPE_STOCK_IN);
            }
            tryFinishWorkorderOnLastProcessComplete(task);
        }

        return 1;
    }

    /**
     * 外协末道工序全部派工完工后，将关联工单置为已完成（对齐 changeStatus 末道逻辑，仅外协报工使用）
     */
    private void tryFinishWorkorderOnLastProcessComplete(ProTask task) {
        if (task == null || task.getIsLastProcess() == null || task.getIsLastProcess() != 1) {
            return;
        }
        if (proTaskService.getNextTaskByTaskId(task.getTaskId()) != null) {
            return;
        }
        QueryWrapper<ProTaskWorkunit> taskWorkunitQuery = new QueryWrapper<>();
        taskWorkunitQuery.eq("task_id", task.getTaskId());
        taskWorkunitQuery.notIn("status", TaskStatusEnum.FINISHED.getStatus());
        if (CollectionUtil.isNotEmpty(proTaskWorkunitService.selectListByQw(taskWorkunitQuery))) {
            return;
        }
        ProWorkorder workorderQuery = new ProWorkorder();
        workorderQuery.setTaskId(task.getTaskId());
        List<ProWorkorder> workorders = proWorkorderService.selectProWorkorderByTaskId(workorderQuery);
        if (CollectionUtil.isEmpty(workorders)) {
            return;
        }
        Set<String> terminalStatuses = new HashSet<>(Arrays.asList(
                WorkorderStatusEnum.FINISHED.getValue(),
                WorkorderStatusEnum.CLOSE.getValue(),
                WorkorderStatusEnum.CANCEL.getValue(),
                WorkorderStatusEnum.CANCELED.getValue()));
        for (ProWorkorder wo : workorders) {
            if (!terminalStatuses.contains(wo.getStatus())) {
                proWorkorderService.updateWorkorderState(wo, WorkorderStatusEnum.FINISHED);
            }
        }
    }

    @Transactional
    @Override
    public int insertObj(ProTaskAssistProcess assistProcess) {
        return 1;
    }

}
