package com.fizz.business.constants.enums;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fizz.business.domain.HalfReturn;
import com.fizz.business.dto.ExitCoilInfoDTO;
import com.fizz.business.dto.MatmapDTO;
import com.fizz.business.form.ChangePlanStatusForm;
import com.fizz.business.form.WebOperateMatForm;
import com.fizz.business.mapper.HalfReturnMapper;
import com.fizz.business.service.CrmPdiPlanService;
import com.fizz.business.service.PdoExCoilService;
import com.fizz.business.service.TrackService;
import com.fizz.business.service.client.RedisCacheManager;
import com.fizz.business.service.impl.BeanFactory;
import com.fizz.business.utils.ErrorDataException;
import com.fizz.business.utils.MatmapUtil;
import com.fizz.business.utils.WebSocketUtil;
import com.fizz.business.vo.CrmPdiPlanVO;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 钢卷操作
 *
 * @author chenhao
 * @date 2023/04/24
 */
@Getter
@Slf4j
@AllArgsConstructor
public enum WebOperateMatEnum implements IEnum<String>, IOperateMat<WebOperateMatForm> {
    ONLINE("上线") {
        @Override
        public void operate(WebOperateMatForm form) {
            Assert.notNull(form.getPorIdx(), "开卷机编号不能为空");
            // 页面手动上卷时，如果开卷机有卷
            // 需要判断：正常卷不允许上卷；虚拟卷则需要手动更新matmap，segment
            MatmapDTO porCoil = MatmapUtil.getMatmap(form.getPorIdx());
            if (MatmapUtil.already(porCoil)) {

                ONLINE.syncPlanStatus(form.getPlanId(), form.getEntryMatId());
                WebSocketUtil.sendSignalMsg(form, true);
                // 如果开卷机和焊机的钢卷相同，则将计划状态变更为生产中
                MatmapDTO welderCoil = MatmapUtil.getMatmap(DeviceEnum.WELDER.getIdx());
                if (MatmapUtil.already(welderCoil) && Objects.equals(form.getEntryMatId(), welderCoil.getMatId())) {
                    form.setOperation(PRODUCING);
                    BeanFactory.getBean(TrackService.class).webOperateMat(form);
                }
            } else {
                ONLINE.syncPlanStatus(form.getPlanId(), form.getEntryMatId());
                ;
                MatmapUtil.setMatmap(form.getPorIdx(), form.getEntryMatId(), form.getPlanId(), form.getPlanNo());
                WebSocketUtil.sendSignalMsg(form);
            }
            // 钢卷上线时, 缓存工艺规程
//            BeanFactory.getBean(RedisCacheManager.class).setCoilSetup(form.getPlanId());
            WebSocketUtil.sendMatmapMsg();
        }
    },
    UNLOAD("卸卷") {
        @Override
        public void operate(WebOperateMatForm form) {
            // 开卷机卸卷,变更计划状态为READY,清除matmap
            if (Objects.nonNull(form.getPorIdx())) {
                UNLOAD.syncPlanStatus(form.getPlanId(), form.getEntryMatId());
                ;
                MatmapUtil.clearMatmap(form.getPorIdx());
                // 删除工艺规程
                BeanFactory.getBean(RedisCacheManager.class).delCoilSetup(form.getEntryMatId());
                WebSocketUtil.sendSignalMsg(form);
                WebSocketUtil.sendMatmapMsg();
            }
            // 卷取机卸卷,清除matmap
            else if (Objects.nonNull(form.getTrIdx())) {
                MatmapUtil.clearMatmap(form.getTrIdx());
                // 移除mergeHead
                BeanFactory.getBean(RedisCacheManager.class).removeMergeHead();
                WebSocketUtil.sendSignalMsg(form);
                WebSocketUtil.sendMatmapMsg();
            } else {
                throw new ErrorDataException(ExceptionCodeEnum.DATA_NOT_FOUND, "卸卷开卷机或卷取机编号不能为空");
            }
        }
    },

    ALL_RETURN("整卷回退") {
        @Override
        public void operate(WebOperateMatForm form) {
            ALL_RETURN.doReturn(form);
        }
    },
    HALF_RETURN("半卷回退") {
        @Override
        public void operate(WebOperateMatForm form) {
            HALF_RETURN.doReturn(form);
        }
    },
    PRODUCING("生产中") {
        @Override
        public void operate(WebOperateMatForm form) {
            PRODUCING.syncPlanStatus(form.getPlanId(), form.getEntryMatId());
            ;
            WebSocketUtil.sendSignalMsg(form);
        }
    },
    PRODUCT("生产完成") {
        @Override
        public void operate(WebOperateMatForm form) {
            PRODUCT.syncPlanStatus(form.getPlanId(), form.getEntryMatId());
            ;
            if (Objects.isNull(form.getCoilLength()) || form.getCoilLength() <= 0) {
                form.setCoilLength(9999d);
            }
            PdoExCoilService pdoExCoilService = BeanFactory.getBean(PdoExCoilService.class);
            MatmapDTO matmapDTO = new MatmapDTO();
            matmapDTO.setMatId(form.getEntryMatId());
            matmapDTO.setPlanId(form.getPlanId());
            ExitCoilInfoDTO exitCoil = pdoExCoilService.genExitCoilInfo(matmapDTO, ExitCutTypeEnum.WELDER_CUT);
            pdoExCoilService.saveExCoil(exitCoil);
            // 2023.9.26 手动完成的计划产出不上报给L3，由操作工手动登记产出
//            SendMqUtil.sendCoilOutputMsg(pdoExCoilDTO);

            // 删除工艺规程
            BeanFactory.getBean(RedisCacheManager.class).delCoilSetup(form.getEntryMatId());
            WebSocketUtil.sendSignalMsg(form);
        }
    },
    BLOCK("卸卷并封闭") {
        @Override
        public void operate(WebOperateMatForm form) {
            BLOCK.syncPlanStatus(form.getPlanId(), form.getEntryMatId());
            ;
            MatmapUtil.clearMatmap(form.getPorIdx());
            // 删除工艺规程
            BeanFactory.getBean(RedisCacheManager.class).delCoilSetup(form.getEntryMatId());
            WebSocketUtil.sendSignalMsg(form);
            WebSocketUtil.sendMatmapMsg();
        }
    },
    PAY_OVER("甩尾") {
        @Override
        public void operate(WebOperateMatForm form) {
            ArrayList<String> status = Lists.newArrayList(PlanStatusEnum.ONLINE.name());
            CrmPdiPlanService planClient = BeanFactory.getBean(CrmPdiPlanService.class);
            CrmPdiPlanVO plan = planClient.getByCoilIdAndOperId(form.getEntryMatId());
            if (Objects.nonNull(plan)) {
                Assert.isTrue(!status.contains(plan.getStatus()), "当前状态[{}]不支持甩尾", plan.getStatus());
            }
            MatmapUtil.clearMatmap(form.getPorIdx());
            WebSocketUtil.sendSignalMsg(form);
            WebSocketUtil.sendMatmapMsg();
        }
    },
    ;

    private final String desc;

    private static final Map<String, WebOperateMatEnum> MAP = new HashMap<>(16);

    static {
        for (WebOperateMatEnum e : WebOperateMatEnum.values()) {
            MAP.put(e.getValue(), e);
        }
    }

    @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
    public static WebOperateMatEnum getByValue(String value) {
        return MAP.get(value);
    }

    @JsonValue
    @Override
    public String getValue() {
        return this.name();
    }

    /**
     * 同步计划状态
     *
     * @param planId 计划id
     */
    private void syncPlanStatus(String planId, String matId) {
        CrmPdiPlanService planClient = BeanFactory.getBean(CrmPdiPlanService.class);

        planClient.changeStatus(ChangePlanStatusForm.builder()
                .operation(this.name())
                .id(planId)
                .matId(matId)
                .build());
    }

    /**
     * 通过计划的halfReturnType字段判断当前卷是回退的头部卷还是尾部卷
     * 1. 头部卷: entryMatId=A01
     * 2. 尾部卷: entryMatId=A01-2, returnMatId=A01。（由于计划号+钢卷号唯一，所以回退的尾部卷生成新计划时，将entryMatId设置为A01-2，真实的原料卷号保存在returnMatId中）
     * 半卷回退上报产出
     * 1. 头部卷产出时，原料卷号：A01, 产出卷号: A01-1, 分卷标识: true, 尾卷标识: false
     * 2. 尾部卷产出时：原料卷号：A01，产出卷号: A01-2, 分卷标识: false, 尾卷标识: true
     *
     * @param form
     */
    private void doReturn(WebOperateMatForm form) {
        if (!Lists.newArrayList(HALF_RETURN, ALL_RETURN).contains(form.getOperation()))
            return;

        CrmPdiPlanService planClient = BeanFactory.getBean(CrmPdiPlanService.class);
        CrmPdiPlanVO plan = planClient.getByCoilIdAndOperId(form.getEntryMatId());

        String entryMatId = form.getEntryMatId();
        String returnMatId = form.getReturnMatId();

        if (Objects.equals(form.getOperation(), HALF_RETURN)) {
            HalfReturnMapper returnMapper = BeanFactory.getBean(HalfReturnMapper.class);

            // 记录回退尾卷信息
            HalfReturn tailCoil = new HalfReturn();
            tailCoil.setEntryMatId(entryMatId);
            tailCoil.setExitMatId(returnMatId);
            tailCoil.setPlanNo(plan.getPlanid());
            tailCoil.setExitMatWeight(0d);
            tailCoil.setReturnMatWeight(form.getReturnWeight());
            tailCoil.setReturnType(HALF_RETURN.name());
            tailCoil.setReturnRemark(form.getReturnRemark());
            tailCoil.setReturnMatTime(LocalDateTime.now());

            returnMapper.insert(tailCoil);
        } else {
            // 整卷回退删除已有产出
            BeanFactory.getBean(PdoExCoilService.class).deleteExistPdo(form.getEntryMatId(), form.getPlanId());
        }

        planClient.changeStatus(ChangePlanStatusForm.builder()
                .operation(this.name())
                .id(form.getPlanId())
                .returnMatId(returnMatId)
                .returnWeight(form.getReturnWeight())
                .build());
        // 更新matmap，matId置空
        MatmapUtil.clearMatmap(form.getPorIdx());
        WebSocketUtil.sendSignalMsg(form);
        WebSocketUtil.sendMatmapMsg();
    }

}
