package cn.estsh.i3plus.ext.mes.pcn.apiservice.controller.busi.jx;

import cn.estsh.i3plus.ext.mes.pcn.api.busi.jx.IJxOqcLastCheckService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.jx.IJxOqcManageService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.OqcLastCheckModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.OqcLastCheckParamModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.jx.JxOqcManageCheckDetailModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.jx.JxOqcManageManualModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.jx.JxOqcManageModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.jx.JxOqcManageParamModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.ResourceEnumUtil;
import cn.estsh.impp.framework.base.controller.MesPcnBaseController;
import cn.estsh.impp.framework.boot.exception.ImppBusiException;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.impp.framework.boot.util.ResultBean;
import cn.estsh.impp.framework.boot.util.ValidatorBean;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author: wangjie
 * @CreateDate: 2021/01/19 15:37
 * @Description:
 **/
@Slf4j
@RestController
@RequestMapping(MesPcnExtConstWords.BASE_URL_MES_PCN_JX)
@Api(tags = "JX出货检验控制层")
public class JxOqcManageController extends MesPcnBaseController {

    @Autowired
    private IJxOqcManageService oqcManageService;

    @Autowired
    private IJxOqcLastCheckService oqcLastCheckService;

    @PostMapping(value = "/oqc-manage/normal/query")
    @ApiOperation(value = "正常检验成品扫描/组件跳转展示数据/切换")
    public ResultBean queryOqcManageData(@RequestBody JxOqcManageParamModel model) {
        try {

            ValidatorBean.beginValid(model)
                    .notNull(MesPcnExtConstWords.USER_INFO, model.getUserInfo())
                    .notNull(MesPcnExtConstWords.USER_ID, model.getUserId())
                    .notNull(MesPcnExtConstWords.ORGANIZE_CODE, model.getOrganizeCode());

            JxOqcManageModel result = oqcManageService.queryOqcManageData(model);

            return ResultBean.success(StringUtils.isEmpty(result.getMsg()) ? "查询成功" : result.getMsg())
                    .setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode()).setResultObject(result);
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        }
    }

    @PostMapping(value = "/oqc-manage/normal/reset")
    @ApiOperation(value = "重置")
    public ResultBean resetOqcManageData(@RequestBody JxOqcManageParamModel model) {
        try {

            ValidatorBean.beginValid(model)
                    .notNull(MesPcnExtConstWords.USER_INFO, model.getUserInfo())
                    .notNull(MesPcnExtConstWords.USER_ID, model.getUserId())
                    .notNull(MesPcnExtConstWords.ORGANIZE_CODE, model.getOrganizeCode());


            JxOqcManageModel result = oqcManageService.resetOqcManageData(model);

            return ResultBean.success(StringUtils.isEmpty(result.getMsg()) ? "重置成功" : result.getMsg())
                    .setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode()).setResultObject(result);
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        }
    }

    @PostMapping(value = "/oqc-manage/normal/oqc-check-detail/update")
    @ApiOperation(value = "修改检验项")
    public ResultBean updateOqcCheckDetail(@RequestBody JxOqcManageCheckDetailModel model) {
        try {

            ValidatorBean.beginValid(model)
                    .notNull(MesPcnExtConstWords.ID_STR, model.getIdStr())
                    .notNull(MesPcnExtConstWords.USER_INFO, model.getUserInfo())
                    .notNull(MesPcnExtConstWords.ORGANIZE_CODE, model.getOrganizeCode());

            oqcManageService.updateOqcCheckDetail(model, model.getUserInfo());
            return ResultBean.success("操作成功").setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode());
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        }
    }

    @PostMapping("/oqc-manage/normal/oqc-check-detail/reload")
    @ApiOperation(value = "重载检验项(成功之后前端调用查询接口)")
    public ResultBean doOqcCheckDetailReload(@RequestBody JxOqcManageParamModel model) {
        try {
            ValidatorBean.beginValid(model)
                    .notNull(MesPcnExtConstWords.OQC_NO, model.getOqcNo())
                    .notNull(MesPcnExtConstWords.USER_INFO, model.getUserInfo())
                    .notNull(MesPcnExtConstWords.USER_ID, model.getUserId())
                    .notNull(MesPcnExtConstWords.ORGANIZE_CODE, model.getOrganizeCode());

            oqcManageService.doOqcCheckDetailReload(model);
            return ResultBean.success("操作成功").setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode());
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        }
    }

    @PostMapping(value = "/oqc-manage/normal/insert")
    @ApiOperation(value = "正常检验生成检验单(成功之后前端调用查询接口)")
    public ResultBean insertOqcManageDataNormal(@RequestBody JxOqcManageParamModel model) {

        String key = new StringJoiner(MesPcnExtConstWords.COLON)
                .add(model.getOrganizeCode()).add(MesPcnExtConstWords.OQC_MANAGE_LOCK).add(model.getWorkOrderNo()).toString();

        RLock lock = (RLock) redisMesPcn.getFairLock(key);

        try {
            if (!lock.tryLock(20, 180, TimeUnit.SECONDS)) {
                log.info("MES-PCN正常检验生成检验单:尝试锁定工单[{}]等待超时,请重试!超时原因:相同工单不能并发操作", model.getWorkOrderNo());
                return ResultBean.fail(ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:尝试锁定工单[%s]等待超时,请重试!超时原因:相同工单不能并发操作", model.getWorkOrderNo())
                        .build());
            }
        } catch (Exception e) {
            log.info("MES-PCN正常检验生成检验单:尝试锁定工单[{}]操作失败,请重试!失败原因:[{}]", model.getWorkOrderNo(), e.getMessage());
            return ResultBean.fail(ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生成检验单:尝试锁定工单[%s]操作失败,请重试!失败原因:[%s]", model.getWorkOrderNo(), e.getMessage())
                    .build());
        }

        try {
            ValidatorBean.beginValid(model)
                    .notNull(MesPcnExtConstWords.WORK_ORDER_NO, model.getWorkOrderNo())
                    .notNull(MesPcnExtConstWords.OQC_NO_TYPE, model.getOqcNoType())
                    .notNull(MesPcnExtConstWords.USER_INFO, model.getUserInfo())
                    .notNull(MesPcnExtConstWords.USER_ID, model.getUserId())
                    .notNull(MesPcnExtConstWords.ORGANIZE_CODE, model.getOrganizeCode());

            oqcManageService.insertOqcManageDataNormal(model);
            return ResultBean.success("操作成功").setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode());
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) lock.unlock();
        }
    }

    @PostMapping(value = "/oqc-manage/normal/update")
    @ApiOperation(value = "正常检验-合格/不合格(成功之后前端调用查询接口)")
    public ResultBean updateOqcManageDataNormal(@RequestBody JxOqcManageParamModel model) {

        String key = new StringJoiner(MesPcnExtConstWords.COLON)
                .add(model.getOrganizeCode()).add(MesPcnExtConstWords.OQC_MANAGE_LOCK).add(model.getWorkOrderNo()).toString();

        RLock lock = (RLock) redisMesPcn.getFairLock(key);

        try {
            if (!lock.tryLock(20, 180, TimeUnit.SECONDS)) {
                log.info("正常检验-合格/不合格:尝试锁定工单[{}]等待超时,请重试!超时原因:相同工单不能并发操作", model.getWorkOrderNo());
                return ResultBean.fail(ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("正常检验-合格/不合格:尝试锁定工单[%s]等待超时,请重试!超时原因:相同工单不能并发操作", model.getWorkOrderNo())
                        .build());
            }
        } catch (Exception e) {
            log.info("正常检验-合格/不合格:尝试锁定工单[{}]操作失败,请重试!失败原因:[{}]", model.getWorkOrderNo(), e.getMessage());
            return ResultBean.fail(ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("正常检验-合格/不合格:尝试锁定工单[%s]操作失败,请重试!失败原因:[%s]", model.getWorkOrderNo(), e.getMessage())
                    .build());
        }

        try {

            ValidatorBean.beginValid(model)
                    .notNull(MesPcnExtConstWords.WORK_ORDER_NO, model.getWorkOrderNo())
                    .notNull(MesPcnExtConstWords.OQC_NO, model.getOqcNo())
                    .notNull(MesPcnExtConstWords.CHECK_RESULT, model.getCheckResult())
                    .notNull(MesPcnExtConstWords.USER_INFO, model.getUserInfo())
                    .notNull(MesPcnExtConstWords.USER_ID, model.getUserId())
                    .notNull(MesPcnExtConstWords.ORGANIZE_CODE, model.getOrganizeCode());

            oqcManageService.updateOqcManageDataNormal(model);
            return ResultBean.success("操作成功").setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode());
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) lock.unlock();
        }
    }

    /*********************** 手动检验 **************************/

    @PostMapping(value = "/oqc-manage/manual/query")
    @ApiOperation(value = "手动检验查询")
    public ResultBean queryOqcManageDataManual(@RequestBody JxOqcManageManualModel model) {
        try {

            ValidatorBean.beginValid(model)
                    .notNull(MesPcnExtConstWords.WORK_ORDER_NO, model.getWorkOrderNo())
                    .notNull(MesPcnExtConstWords.WORK_TIME, model.getWorkTime())
                    .notNull(MesPcnExtConstWords.SHIFT_CODE, model.getShiftCode())
                    .notNull(MesPcnExtConstWords.WORK_CENTER_CODE, model.getWorkCenterCode())
                    .notNull(MesPcnExtConstWords.PART_NO, model.getPartNo())
                    .notNull(MesPcnExtConstWords.USER_INFO, model.getUserInfo())
                    .notNull(MesPcnExtConstWords.ORGANIZE_CODE, model.getOrganizeCode());

            JxOqcManageManualModel result = oqcManageService.queryOqcManageDataManual(model);

            return ResultBean.success(StringUtils.isEmpty(result.getMsg()) ? "查询成功" : result.getMsg())
                    .setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode()).setResultObject(result);
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        }
    }

    @PostMapping(value = "/oqc-manage/manual/insert")
    @ApiOperation(value = "手动检验提交")
    public ResultBean insertOqcManageDataManual(@RequestBody JxOqcManageManualModel model) {

        String key = new StringJoiner(MesPcnExtConstWords.COLON)
                .add(model.getOrganizeCode()).add(MesPcnExtConstWords.OQC_MANAGE_LOCK).add(model.getWorkOrderNo()).toString();

        RLock lock = (RLock) redisMesPcn.getFairLock(key);

        try {
            if (!lock.tryLock(20, 180, TimeUnit.SECONDS)) {
                log.info("手动检验提交:尝试锁定工单[{}]等待超时,请重试!超时原因:相同工单不能并发操作", model.getWorkOrderNo());
                return ResultBean.fail(ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("手动检验提交:尝试锁定工单[%s]等待超时,请重试!超时原因:相同工单不能并发操作", model.getWorkOrderNo())
                        .build());
            }
        } catch (Exception e) {
            log.info("手动检验提交:尝试锁定工单[{}]操作失败,请重试!失败原因:[{}]", model.getWorkOrderNo(), e.getMessage());
            return ResultBean.fail(ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("手动检验提交:尝试锁定工单[%s]操作失败,请重试!失败原因:[%s]", model.getWorkOrderNo(), e.getMessage())
                    .build());
        }

        try {

            ValidatorBean.beginValid(model)
                    .notNull(MesPcnExtConstWords.WORK_ORDER_NO, model.getWorkOrderNo())
                    .notNull(MesPcnExtConstWords.WORK_TIME, model.getWorkTime())
                    .notNull(MesPcnExtConstWords.SHIFT_CODE, model.getShiftCode())
                    .notNull(MesPcnExtConstWords.WORK_CENTER_CODE, model.getWorkCenterCode())
                    .notNull(MesPcnExtConstWords.PART_NO, model.getPartNo())
                    .notNull(MesPcnExtConstWords.USER_INFO, model.getUserInfo())
                    .notNull(MesPcnExtConstWords.ORGANIZE_CODE, model.getOrganizeCode());

            JxOqcManageManualModel result = oqcManageService.insertOqcManageDataManual(model);

            return ResultBean.success(StringUtils.isEmpty(result.getMsg()) ? "操作成功" : result.getMsg())
                    .setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode()).setResultObject(result);
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) lock.unlock();
        }
    }

    /*********************** 手动检验 **************************/

    /************************* 总检验结果 *************************/

    @GetMapping(value = "/last-check/query")
    @ApiOperation(value = "总检验结果分页查询")
    public ResultBean queryOqcLastCheckPager(OqcLastCheckModel model, Pager pager) {
        try {
            ValidatorBean.beginValid(model)
                    .notNull(MesPcnExtConstWords.ORGANIZE_CODE, model.getOrganizeCode());
            ListPager listPager = oqcLastCheckService.queryOqcLastCheckPager(model, pager);
            return ResultBean.success("查询成功").setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode())
                    .setListPager(listPager).setResultObject(new OqcLastCheckModel(!CollectionUtils.isEmpty(listPager.getObjectList())));
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        }
    }

    @PostMapping("/last-check/update")
    @ApiOperation(value = "修改总检验单结果")
    public ResultBean updateOutPutStatisticsOqcCheck(@RequestBody OqcLastCheckParamModel model) {

        try {
            ValidatorBean.beginValid(model)
                    .notNull(MesPcnExtConstWords.USER_INFO, model.getUserInfo())
                    .notNull(MesPcnExtConstWords.ORGANIZE_CODE, model.getOrganizeCode());
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        }

        Map<String, String> workOrderNoList = CollectionUtils.isEmpty(model.getModelList()) ? null :
                model.getModelList().stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkOrderNo()) && !StringUtils.isEmpty(o.getOrganizeCode())))
                        .collect(Collectors.toMap(OqcLastCheckParamModel::getWorkOrderNo, o -> new StringJoiner(MesPcnExtConstWords.COLON).add(o.getOrganizeCode()).add(MesPcnExtConstWords.BU_OQC_MANAGE_LOCK).add(o.getWorkOrderNo()).toString()));

        if (CollectionUtils.isEmpty(workOrderNoList)) {
            return ResultBean.fail(ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("入参缺少必要参数")
                    .build());
        }

        List<RLock> keyList = new ArrayList<>();

        for (String workOrderNo : workOrderNoList.keySet()) {
            if (StringUtils.isEmpty(workOrderNo)) continue;
            RLock lock = (RLock) redisMesPcn.getFairLock(workOrderNoList.get(workOrderNo));
            try {
                if (!lock.tryLock(20, 180, TimeUnit.SECONDS)) {
                    if (!CollectionUtils.isEmpty(keyList)) {
                        for (RLock o : keyList) {
                            if (o.isLocked() && o.isHeldByCurrentThread()) o.unlock();
                        }
                    }

                    log.info("MES-PCN修改总检验单结果:尝试锁定工单[{}]等待超时,请重试!超时原因:相同工单不能并发操作", workOrderNo);
                    return ResultBean.fail(ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("修改总检验单结果:尝试锁定工单[%s]等待超时,请重试!超时原因:相同工单不能并发操作", workOrderNo)
                            .build());
                }
            } catch (Exception e) {
                if (!CollectionUtils.isEmpty(keyList)) {
                    for (RLock o : keyList) {
                        if (o.isLocked() && o.isHeldByCurrentThread()) o.unlock();
                    }
                }

                log.info("MES-PCN修改总检验单结果:尝试锁定工单[{}]操作失败,请重试!失败原因:[{}]", workOrderNo, e.getMessage());
                return ResultBean.fail(ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("修改总检验单结果:尝试锁定工单[%s]操作失败,请重试!失败原因:[%s]", workOrderNo, e.getMessage())
                        .build());
            }
            keyList.add(lock);
        }

        try {
            oqcLastCheckService.updateOutPutStatisticsOqcCheck(model);
            return ResultBean.success("修改成功").setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode());
        } catch (ImppBusiException busExcep) {
            return ResultBean.fail(busExcep);
        } catch (Exception e) {
            return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
        } finally {
            if (!CollectionUtils.isEmpty(keyList)) {
                for (RLock o : keyList) {
                    if (o.isLocked() && o.isHeldByCurrentThread()) o.unlock();
                }
            }
        }
    }

    /************************* 总检验结果 *************************/
}
