package com.sw.mes.yb.accessory.service.impl;


import com.alibaba.fastjson.JSON;
import com.sw.mes.base.factory.material.entity.MaterialModel;
import com.sw.mes.base.factory.material.service.MaterialModelService;
import com.sw.mes.core.api.auth.AuthFeignClient;
import com.sw.mes.core.api.system.StoreFeignClients;
import com.sw.mes.core.dto.auth.UserDto;
import com.sw.mes.core.dto.store.StoreOperatorDetailDto;
import com.sw.mes.core.dto.store.StoreOperatorDto;
import com.sw.mes.core.enums.EnumValues;
import com.sw.mes.core.enums.StoreBusinessTypeEnum;
import com.sw.mes.core.enums.StoreOperatorTypeEnum;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.base.factory.init.entity.Equipment;
import com.sw.mes.base.factory.init.service.EquipmentService;
import com.sw.mes.base.factory.material.entity.Unit;
import com.sw.mes.yb.accessory.dao.AccessoryApplyDao;
import com.sw.mes.yb.accessory.dto.AccessoryApplyDto;
import com.sw.mes.yb.accessory.dto.IdDto;
import com.sw.mes.yb.accessory.entity.*;
import com.sw.mes.yb.accessory.service.*;
import com.sw.mes.core.base.BaseServiceImpl;
import com.sw.mes.core.context.BaseContextHandler;
import com.sw.mes.yb.accessory.vo.RequestWmsVo;
import com.sw.mes.yb.accessory.vo.ToMaterialApplyVo;
import com.sw.mes.yb.accessory.vo.WmsResult;
import com.sw.mes.yb.pad.dto.AgvResult;
import com.sw.mes.yb.production.entity.EquipmentExtendState;
import com.sw.mes.yb.production.service.EquipmentExtendStateService;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * @Author
 * @Description：
 * @Date: Create in
 * @Modified By:
 */
@Service
@Transactional
public class AccessoryApplyServiceImpl extends BaseServiceImpl<AccessoryApply> implements AccessoryApplyService {

    @Autowired
    ModelMapper modelMapper;

    AccessoryApplyDao dao;

    @Autowired
    public void setDao(AccessoryApplyDao dao) {
        super.setBaseDao(dao);
        this.dao = dao;
    }

    @Autowired
    private EquipmentAccessoryService equipmentAccessoryService;

    @Autowired
    private AuthFeignClient authFeignClient;

    @Autowired
    private AccessoryReturnService accessoryReturnService;

    @Autowired
    private EquipmentService equipmentService;

    @Autowired
    private AccessoryMaterialService accessoryMaterialService;



    @Autowired
    private AccessoryLogService accessoryLogService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private AccessoryApplyService accessoryApplyService;

    @Autowired
    private EquipmentExtendStateService equipmentExtendStateService;

    @Autowired
    private AccessoryDiscardService accessoryDiscardService;

    @Autowired
    private StoreFeignClients storeFeignClients;

    @Autowired
    private MaterialModelService materialModelService;

//    @Value("${wms.url}")
    private String wmsUrl;

    private static final String applyWms = "api/YC6MES/otherinteraction"; //TODO

    @Override
    public AccessoryApply findByGoodsCodeAndState(String goodsCode, String state) {
        List<AccessoryApply> accessoryApplies = dao.findByGoodsCodeAndState(goodsCode, state);
        if (accessoryApplies != null && accessoryApplies.size() > 0) {
            return accessoryApplies.get(0);
        }
        return null;
    }

    @Override
    public AccessoryApply findByGoodsCodeAndEquipmentIdAndState(String goodsCode, Long equipmentId, String state) {
        List<AccessoryApply> accessoryApplies = dao.findByGoodsCodeAndEquipmentIdAndState(goodsCode, equipmentId, state);
        if (accessoryApplies != null && accessoryApplies.size() > 0) {
            return accessoryApplies.get(0);
        }
        return null;
    }

    @Override
    public void apply(IdDto dto) throws RuntimeException {
        EquipmentAccessory accessory = equipmentAccessoryService.get(dto.getId());
        if (accessory == null) {
            throw new RuntimeException("监控信息不存在！");
        }
        AccessoryReturn accessoryReturn = accessoryReturnService.findByAccessoryId(accessory.getId().intValue());

        if (
                accessory.getApplyButton() == 0
        )
        {
            throw new RuntimeException("请先退库再申请要料！");
        }

        if (accessoryReturn == null){
            throw new RuntimeException("缺失对应的退库记录！");
        }

        if (!accessory.getGoodsCode().equals(accessoryReturn.getGoodsCode())){
            if (EnumValues.AccessoryReturnStatus.NOTCONFIRMED.getKey().equals(accessoryReturn.getState())){
                throw new RuntimeException("之前的退库请求还没被处理！");
            }
        } //防止先退库，再申请要料，要料出库后，还没处理之前的退库请求，再要料的现象发生。


        AccessoryApply oldApply = findByApplyDateAndGoodsCode(accessoryReturn.getApplyDate(), accessory.getGoodsCode());
        if (oldApply != null && EnumValues.PickInfoStatus.NOTCONFIRMED.getKey().equals(oldApply.getState())) {
            throw new RuntimeException("当前监控有要料申请正在处理");
        }

//        AccessoryDiscard accessoryDiscard = accessoryDiscardService.findByReturnId(accessoryReturn.getId());
//        if (accessoryDiscard.getOpinionOfProduct() == null && accessoryDiscard.getOpinionOfTechnology() == null && accessoryDiscard.getOpinionOfQuality() == null){
//            throw new RuntimeException("该寿命监控报废记录还未被审核！");
//        }

        AccessoryApply apply = new AccessoryApply();
        Result<UserDto> user = authFeignClient.getUserById(BaseContextHandler.getUserID());
        if (user != null && user.getData()!=null){
            apply.setApplyUserNo(user.getData().getWorkNo());
        }
        apply.setApplyDate(new Date());
        apply.setApplyUser(BaseContextHandler.getUsername());
        EquipmentExtendState equipmentExtendState = equipmentExtendStateService.getByCode(accessory.getEquipment().getCode());
        if (equipmentExtendState != null){
            apply.setUserClassNo(equipmentExtendState.getClassNo());
            apply.setUserTeamGroup(equipmentExtendState.getTeamGroup());
        }
        apply.setEquipment(accessory.getEquipment());
        apply.setGoodsCode(accessory.getGoodsCode());
        apply.setMaterial(accessory.getMaterial());
        if (dto.getNum() == null) {
            dto.setNum(1);
        }
        apply.setNum(dto.getNum());
        apply.setReason(dto.getReason());
        apply.setState(EnumValues.PickInfoStatus.NOTCONFIRMED.getKey());
        apply.setPickNo(getPickNo(Optional.of(accessory).map(EquipmentAccessory::getEquipment).map(Equipment::getCode).orElse("")));
        apply.setEquipmentAccessory(accessory);
        saveOrUpdate(apply);

        accessory.setApplyDate(apply.getApplyDate());
        accessory.setApplyUser(apply.getApplyUser());
//        accessory.setApplyButton(0);
        equipmentAccessoryService.saveOrUpdate(accessory);

        //线边仓要料申请
        StoreOperatorDto storeOperatorDto = buildStoreOperatorDto(apply);
        Result result = storeFeignClients.createOutputForSite(storeOperatorDto);
        if (result == null || !result.getCode().equals(200)){
            throw new RuntimeException("远程调用storeFeignClients.createForSite生成出库申请单失败:"+Optional.ofNullable(result).map(Result::getMessage).orElse(""));
        }
    }

    private StoreOperatorDto buildStoreOperatorDto(AccessoryApply apply) {
        StoreOperatorDto storeOperatorDto = new StoreOperatorDto();
        List<StoreOperatorDetailDto> list = new ArrayList<>();

        storeOperatorDto.setStoreBusinessTypeEnum(StoreBusinessTypeEnum.辅料申请);
        storeOperatorDto.setStoreOperatorTypeEnum(StoreOperatorTypeEnum.正常出库);
        storeOperatorDto.setDeviceNo(apply.getEquipment().getCode());
        storeOperatorDto.setOrderNo(apply.getPickNo());
        storeOperatorDto.setRemark(apply.getReason());
        storeOperatorDto.setReceiverCode(BaseContextHandler.getUserID().toString());
        storeOperatorDto.setReceiverName(BaseContextHandler.getUsername());

        StoreOperatorDetailDto detailDto = new StoreOperatorDetailDto();
        MaterialModel model = materialModelService.findByCode(apply.getMaterial().getCodes());
        if (model == null) {
            throw new RuntimeException("物料主数据缺失料号为"+apply.getMaterial().getCodes()+"的模型");
        }
        detailDto.setMaterialModelId(model.getId());
        detailDto.setMaterialModelCode(model.getCode());
        detailDto.setMaterialModelName(model.getName());
        detailDto.setNum(new BigDecimal(apply.getNum()));
        detailDto.setUnitName(Optional.of(model).map(MaterialModel::getUnit).map(Unit::getName).orElse(""));
        detailDto.setSupplierName(model.getSupplier());

        list.add(detailDto);
        storeOperatorDto.setBusinessData(list);
        return storeOperatorDto;
    }

    public String getPickNo(String deviceNo) {
        StringBuilder str = new StringBuilder();
        str.append("YLFL");
//        str.append("-");
        str.append(deviceNo);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String format = sdf.format(new Date());
        str.append(format);
        String uuid = UUID.randomUUID().toString();
        String substring = uuid.substring(0, 5);
//        str.append("-");
        str.append(substring);
        return str.toString();
    }

    @Override
    public void cancel(Long id) {

        AccessoryApply apply = get(id);
        if (apply != null) {
            apply.setState(EnumValues.PickInfoStatus.CANCEL.getKey());
            apply.setStateDate(new Date());

            saveOrUpdate(apply);
        }

    }

    @Override
    public void apply1(AccessoryApplyDto dto) {
        Equipment equipment = equipmentService.findByCode(dto.getEquipmentCode());
        AccessoryMaterial accessoryMaterial = accessoryMaterialService.findByCodes(dto.getMaterialCodes());
        EquipmentAccessory equipmentAccessory = equipmentAccessoryService.getByEquipment_idAndMaterial_id(equipment.getId(), accessoryMaterial.getId());

        if(equipmentAccessory == null){
            throw new RuntimeException("不存在设备"+dto.getEquipmentCode()+"与料号"+dto.getMaterialCodes()+"绑定的热场监控");
        }

        AccessoryReturn accessoryReturn = accessoryReturnService.findByAccessoryId(equipmentAccessory.getId().intValue());

        if (
                equipmentAccessory.getApplyButton() == 0
        )
        {
            throw new RuntimeException("请先退库再申请要料！");
        }

        if (accessoryReturn == null){
            throw new RuntimeException("缺失对应的退库记录！");
        }

        if (!equipmentAccessory.getGoodsCode().equals(accessoryReturn.getGoodsCode())){
            if (EnumValues.AccessoryReturnStatus.NOTCONFIRMED.getKey().equals(accessoryReturn.getState())){
                throw new RuntimeException("之前的退库请求还没被处理！");
            }
        } //防止先退库，再申请要料，要料出库后，还没处理之前的退库请求，再要料的现象发生。

        AccessoryApply oldApply = findByApplyDateAndGoodsCode(accessoryReturn.getApplyDate(), equipmentAccessory.getGoodsCode());
        if (oldApply != null && EnumValues.PickInfoStatus.NOTCONFIRMED.getKey().equals(oldApply.getState())) {
            throw new RuntimeException("当前监控有要料申请正在处理");
        }

        AccessoryApply apply = new AccessoryApply();
        Result<UserDto> user = authFeignClient.getUserById(BaseContextHandler.getUserID());
        if (user != null && user.getData()!=null){
            apply.setApplyUserNo(user.getData().getWorkNo());
        }
        apply.setApplyDate(new Date());
        apply.setApplyUser(BaseContextHandler.getUsername());
        EquipmentExtendState equipmentExtendState = equipmentExtendStateService.getByCode(equipmentAccessory.getEquipment().getCode());
        if (equipmentExtendState != null){
            apply.setUserClassNo(equipmentExtendState.getClassNo());
            apply.setUserTeamGroup(equipmentExtendState.getTeamGroup());
        }
        apply.setEquipment(equipmentAccessory.getEquipment());
        apply.setGoodsCode(equipmentAccessory.getGoodsCode());
        apply.setMaterial(equipmentAccessory.getMaterial());
        if (dto.getNum() == null) {
            dto.setNum(1);
        }
        apply.setNum(dto.getNum());
        apply.setReason(dto.getReason());
        apply.setState(EnumValues.PickInfoStatus.NOTCONFIRMED.getKey());
        apply.setPickNo(getPickNo(Optional.of(equipmentAccessory).map(EquipmentAccessory::getEquipment).map(Equipment::getCode).orElse("")));
        apply.setEquipmentAccessory(equipmentAccessory);
        saveOrUpdate(apply);

        equipmentAccessory.setApplyDate(apply.getApplyDate());
        equipmentAccessory.setApplyUser(apply.getApplyUser());
//        equipmentAccessory.setApplyButton(0);
        equipmentAccessoryService.saveOrUpdate(equipmentAccessory);

        //线边仓要料申请
        StoreOperatorDto storeOperatorDto = buildStoreOperatorDto(apply);
        Result result = storeFeignClients.createOutputForSite(storeOperatorDto);
        if (result == null || !result.getCode().equals(200)){
            throw new RuntimeException("远程调用storeFeignClients.createForSite生成出库申请单失败:"+Optional.ofNullable(result).map(Result::getMessage).orElse(""));
        }
    }

    @Override
    public AccessoryApply findByPickNo(String pickNo){
        List<AccessoryApply> list = dao.findByPickNo(pickNo);
        if (list != null && list.size() > 0){
            return list.get(0);
        }
        return null;
    }

    /**
     * 因为先退库再要料的特性
     * 查询要料时间大于退库时间的要料记录
     * @param applyDate
     * @param goodsCode
     * @return
     */
    @Override
    public AccessoryApply findByApplyDateAndGoodsCode(Date applyDate, String goodsCode) {
        List<AccessoryApply> list = dao.findByApplyDateAndGoodsCode(applyDate, goodsCode);
        if (list != null && list.size() > 0){
            return list.get(0);
        }
        return null;
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public String toWmsApply(RequestWmsVo requestWmsVo, AccessoryLog accessoryLog, String url) {
        try{
            if("-1".equals(wmsUrl)){
                return "200";
            }
            ResponseEntity<String> result = null;
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
            String content = JSON.toJSONString(requestWmsVo);
            HttpEntity<String> request = new HttpEntity<>(content, headers);

            result = restTemplate.postForEntity(url,request, String.class);
            String resultJson = result.getBody();
            accessoryLog.setResult(resultJson);
            if (StringUtils.isNotBlank(resultJson)) {
                //解析状态码，判断成功状态码，失败抛异常回滚，
                WmsResult wmsResult = JSON.parseObject(resultJson, WmsResult.class); //
                if("S".equals(wmsResult.getZtype())) {
                    accessoryLog.setResult(wmsResult.getZmessage());
                    accessoryLogService.saveOrUpdate(accessoryLog);
                    return "200";
                }else {
                    accessoryLog.setType("error");
                    accessoryLog.setResult(wmsResult.getZmessage());
                    accessoryLogService.saveOrUpdate(accessoryLog);
                    return  "wms："+wmsResult.getZmessage();
                }
            }else {
                accessoryLog.setType("error1");
                accessoryLog.setResult("请求wms空！");
                accessoryLogService.saveOrUpdate(accessoryLog);
                return "wms：空！";
            }
        }catch (Exception e){
            accessoryLog.setType("error2");
            accessoryLog.setResult("请求wms失败！");
            accessoryLogService.saveOrUpdate(accessoryLog);
            e.printStackTrace();
            return "wms：请求失败！"+e.getMessage();
        }
    }

    @Override
    public void cancelByOrderNum(String orderNum) {
        AccessoryApply apply = findByPickNo(orderNum);
        if (apply != null) {
            apply.setState(EnumValues.PickInfoStatus.CANCEL.getKey());
            apply.setStateDate(new Date());

            saveOrUpdate(apply);
        }
    }

}
