package com.sw.mes.wms.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.sw.mes.base.system.entity.SysLog;
import com.sw.mes.core.base.BaseServiceImpl;
import com.sw.mes.core.context.BaseContextHandler;
import com.sw.mes.core.response.ResultWms;
import com.sw.mes.core.utils.IpUtils;
import com.sw.mes.rabbitmq.constants.RoutingKey;
import com.sw.mes.rabbitmq.enums.ExchangeEnum;
import com.sw.mes.rabbitmq.enums.QueueEnum;
import com.sw.mes.rabbitmq.service.RabbitMqService;
import com.sw.mes.wms.dao.ReportWmsRecordDao;
import com.sw.mes.wms.dto.ReportWmsDto;
import com.sw.mes.wms.dto.ReportWmsRecordDto;
import com.sw.mes.wms.entity.ReportWmsRecord;
import com.sw.mes.wms.service.ReportWmsRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
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.util.*;
import java.util.stream.Collectors;


/**
* @Author
* @Description：
* @Date: Create in
* @Modified By:
*/
@Service
@Transactional
@Slf4j
public class ReportWmsRecordServiceImpl extends BaseServiceImpl<ReportWmsRecord> implements ReportWmsRecordService {

    @Value("${spring.wmsServiceUrl}")
    private String wmsUrl;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RabbitMqService rabbitMqService;

    @Autowired
    private ReportWmsRecordService reportWmsRecordService;

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

    @Override
//    @Async
    @Transactional(rollbackFor = Throwable.class)
    public void report(List<ReportWmsRecordDto> reportWmsRecordDtos) {
        //TODO 请求wms
        List<ReportWmsDto> list = buildReportWmsDto(reportWmsRecordDtos);
        ResultWms resultWms = sendReportWms(list);

        if (resultWms != null){
            if ("1".equals(resultWms.getCode())){
                //请求成功则保存成功的报工记录
                List<ReportWmsRecord> collect = reportWmsRecordDtos.stream().map(item -> {
                    ReportWmsRecord record = toEntity(item);
                    record.setStatus(1);
                    return record;
                }).collect(Collectors.toList());
                dao.saveAll(collect);
            }else if ("0".equals(resultWms.getCode())){
                //请求失败则保存失败的报工记录
                List<ReportWmsRecord> collect = reportWmsRecordDtos.stream().map(item -> {
                    ReportWmsRecord record = toEntity(item);
                    record.setStatus(0);
                    record.setReason(resultWms.getMsg());
                    return record;
                }).collect(Collectors.toList());
                reportWmsRecordService.saveReportWmsRecordWithoutTransactional(collect);
                throw new RuntimeException("报工wms失败，状态码:"+resultWms.getCode()+"/"+resultWms.getMsg());
            }else {
                //请求失败则保存失败的报工记录
                List<ReportWmsRecord> collect = reportWmsRecordDtos.stream().map(item -> {
                    ReportWmsRecord record = toEntity(item);
                    record.setStatus(0);
                    record.setReason(resultWms.getMsg());
                    return record;
                }).collect(Collectors.toList());
                reportWmsRecordService.saveReportWmsRecordWithoutTransactional(collect);
                throw new RuntimeException("报工wms失败，状态码未知:"+resultWms.getCode()+"/"+resultWms.getMsg());
            }
        }else {
            //请求失败则保存失败的报工记录
            List<ReportWmsRecord> collect = reportWmsRecordDtos.stream().map(item -> {
                ReportWmsRecord record = toEntity(item);
                record.setStatus(0);
                record.setReason("报工wms接口请求失败");
                return record;
            }).collect(Collectors.toList());
            reportWmsRecordService.saveReportWmsRecordWithoutTransactional(collect);
            throw new RuntimeException("报工wms接口请求失败");
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
    public void saveReportWmsRecordWithoutTransactional(List<ReportWmsRecord> collect) {
        dao.saveAll(collect);
    }

    private ReportWmsRecord toEntity(ReportWmsRecordDto item) {
        ReportWmsRecord record = new ReportWmsRecord();
        record.setNo(item.getNo());
        record.setType(item.getType());
        record.setCreateTime(item.getCreateTime());
        record.setCreateUser(item.getCreateUser());
        record.setPlanNo(item.getPlanNo());
        record.setMaterialNo(item.getMaterialNo());
        record.setMaterialQty(item.getMaterialQty());
        record.setSpecification(item.getSpecification());
        record.setUnit(item.getUnit());
        record.setLength(item.getLength());
        record.setWidth(item.getWidth());
        record.setRemark(item.getRemark());
        return record;
    }

    private ResultWms sendReportWms(List<ReportWmsDto> list) {
        String requestName = "报工给wms";
	    String url = wmsUrl + "api/OfflineSemiProduct";
        String returnStr;
        boolean isErr = false;
        String requestId = UUID.randomUUID().toString();
        try {
            HttpHeaders headers = new HttpHeaders();
            MediaType mediaType = MediaType.parseMediaType("application/json; charset=UTF-8");
            headers.setContentType(mediaType);
            headers.add("Accept", MediaType.APPLICATION_JSON.toString());
            HttpEntity<List<ReportWmsDto>> httpEntity = new HttpEntity<>(list, headers);
            ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
            returnStr = exchange.getBody();
        }catch (Exception e){
            e.printStackTrace();
            log.error("报工wms_http请求失败", e);
            returnStr = e.getMessage();
            isErr = true;
        }

        try{
            SysLog syslog = new SysLog();
            syslog.setCreateTime(new Date());
            syslog.setType("info");
            syslog.setCreateUserId(BaseContextHandler.getUserID());
            syslog.setCreateUserName("SYSTEM");
            syslog.setContent(JSON.toJSONString(list));
            syslog.setResult(returnStr);
            syslog.setMethodName("sendReportWms()");
            syslog.setStatus(1);
            syslog.setName(requestName);
            syslog.setServerAddr(url);
            syslog.setReqType("HTTP");
            syslog.setRequestId(requestId);
            syslog.setReqIp(IpUtils.getLocalIP());
            rabbitMqService.sendMessage(JSONObject.toJSONString(syslog), ExchangeEnum.SYS_LOG_EXCHANGE, QueueEnum.SYS_LOG_QUEUE, RoutingKey.SYS_LOG_KEY);
        } catch (Exception e) {
            log.error(requestName+"_"+requestId, e);
            e.printStackTrace();
        }

        if (isErr){
            return null;
        }else {
            return JSON.parseObject(returnStr, new TypeReference<ResultWms>(){});
        }
    }

    private List<ReportWmsDto> buildReportWmsDto(List<ReportWmsRecordDto> reportWmsRecordDtos) {
        return reportWmsRecordDtos.stream().map(this::toWmsDto).collect(Collectors.toList());
    }

    private ReportWmsDto toWmsDto(ReportWmsRecordDto item) {
        ReportWmsDto reportWmsDto = new ReportWmsDto();
        reportWmsDto.setPlanNo(Optional.of(item).map(ReportWmsRecordDto::getPlanNo).orElse(""));
        reportWmsDto.setMaterialNo(Optional.of(item).map(ReportWmsRecordDto::getMaterialNo).orElse(""));
        reportWmsDto.setBatchNo(Optional.of(item).map(ReportWmsRecordDto::getNo).orElse(""));
        reportWmsDto.setMaterialQty(Optional.of(item).map(ReportWmsRecordDto::getMaterialQty).map(Objects::toString).orElse(""));
        reportWmsDto.setSpecification(Optional.of(item).map(ReportWmsRecordDto::getSpecification).orElse(""));
        reportWmsDto.setUnit(Optional.of(item).map(ReportWmsRecordDto::getUnit).orElse(""));
        reportWmsDto.setLength(Optional.of(item).map(ReportWmsRecordDto::getLength).map(Objects::toString).orElse(""));
        reportWmsDto.setWidth(Optional.of(item).map(ReportWmsRecordDto::getWidth).map(Objects::toString).orElse(""));
        reportWmsDto.setRemark(Optional.of(item).map(ReportWmsRecordDto::getRemark).orElse(""));
        return reportWmsDto;
    }
}
