package com.hzjt.service;

import cn.hutool.json.JSONUtil;
import com.hzjt.domain.*;
import com.hzjt.mapper.SbtdspsrMapper;
import com.hzjt.mapper.TraffdevicewriteresultMapper;
import com.hzjt.util.ThreadPoolUtil;
import com.hzjt.util.TransHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

@Service
@Slf4j
public class TraffdevicewriteresultService {

    @Autowired
    private RestTemplate restTemplate;
    @Value("${qingzhi.devicewrite.url}")
    private String url;
    @Value("${qingzhi.devicewrite.timeout}")
    private Integer timeout;

    @Autowired
    private TraffdevicewriteresultMapper traffdevicewriteresultMapper;

    @Autowired
    SbtdspsrMapper sbtdspsrMapper;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Value("${qingzhi.devicewritesupplier.name}")
    String devicesupplier;
    @Value("${qingzhi.redis.token}")
    String qztoken;

    @Value("${qingzhi.devicewrite.url}")
    String devicewriteurl;

    private static CompletionService<ResultObj> threadService  = new ExecutorCompletionService<ResultObj>(ThreadPoolUtil.getPool());

    public List<ResultObj> sendDevices(List<String> xhs) {
        List<SbtdspsrParams> sbtdspsrs = traffdevicewriteresultMapper.querySbtdspsrByXh(xhs);
        List<ResultObj> resultObj = new ArrayList<>();
        try {
            Traffdevicewriteresult param = new Traffdevicewriteresult();

            for (SbtdspsrParams val : sbtdspsrs) {
                threadService.submit(() -> {
                    ResultObj obj = sendToGuangda(val, param);
                    obj.setData(val.getSbbh() + "_" + val.getTdbh());
                    return obj;

                });
            }
            for (int i = 0; i < sbtdspsrs.size(); i++) {
                resultObj.add(threadService.poll(10, TimeUnit.SECONDS).get());
            }

        } catch (Exception e) {
            log.error("devicewrite - sendEvent 异常:" + e.toString());
            resultObj.add(ResultObj.error(ResponseEnum.E_9999.getCode(), e.toString()));
        }
        return resultObj;
    }

    public ResultObj sendToGuangda(SbtdspsrParams val, Traffdevicewriteresult param) throws Exception {
        if (val.getXzbh() == null) {
            log.error("deviceWritePost  {} : regist remsg...", "设备所属单位机构编码必填");
            return ResultObj.error(ResponseEnum.E_1002.getCode(), "设备所属单位机构编码必填");
        } else if (val.getDeviceconfig() == null) {
            log.error("deviceWritePost  {} : regist remsg...", "请impn先配置设备推送配置");
            return ResultObj.error(ResponseEnum.E_1002.getCode(), "请impn先配置设备推送配置");
        } else {
            //转成第三方对象
            DeviceWriteParam item = JSONUtil.toBean(val.getDeviceconfig(), DeviceWriteParam.class);
            item.setDeviceID(val.getWbbh());
            item.setDeviceName(val.getTdmc());
            item.setRegionID(val.getXzbh());
            item.setDeviceStatus(1);
            item.setDeviceSupplier(devicesupplier);
            item.setDataType(1);
            WriteResultObj writeResultObj=null;
            try {
                //调用第三方的restful
                writeResultObj = deviceWritePost(item);
            }
            catch (TimeoutException e) {
                log.error("eventwrite - sendEvents 请求超时:" + e.toString());
                return ResultObj.error(ResponseEnum.E_1008.getCode(), ResponseEnum.E_1008.getMsg());
            } catch (Exception e) {
                log.error("eventwrite - sendEvents 异常:" + e.toString());
                return ResultObj.error(ResponseEnum.E_9999.getCode(), e.toString());
            }
            if (writeResultObj == null) {
                return ResultObj.error(ResponseEnum.E_9999.getCode(), "token凭证获取失败");
            }
            param.setSbbh(val.getSbbh());
            param.setTdbh(val.getTdbh());
            Traffdevicewriteresult traffdevicewriteresult = traffdevicewriteresultMapper.selectOne(param);

            param.setPushdesc(writeResultObj.getMessage());
            param.setXzbh(val.getXzbh());
            param.setPushcount(1L);
            if (writeResultObj.getStatus() == 200) {
                param.setPushstatus(Long.valueOf(0));
            } else {
                param.setPushstatus(Long.valueOf(1));
            }
            //数据库记录操作
            if (traffdevicewriteresult == null) {
                traffdevicewriteresultMapper.insertSelective(param);
            } else {
                if (traffdevicewriteresult.getPushstatus() == 0) {
                    param.setPushstatus(Long.valueOf(0));
                    param.setPushcount(traffdevicewriteresult.getPushcount() + 1);
                }
                traffdevicewriteresultMapper.updateByPrimaryKeySelective(param);
            }
            if (writeResultObj.getStatus() == 200) {
                param.setPushstatus(Long.valueOf(0));
                return ResultObj.ok(writeResultObj.getStatus());
            } else {
                param.setPushstatus(Long.valueOf(1));
                return ResultObj.error(writeResultObj.getStatus(), writeResultObj.getMessage());
            }
        }

    }

    public ResultObj updateAndRegist(SbtdspsrParam sbtdspsr) {
        ResultObj res;
        String pushdesc;
        long pushstatus = 0;
        assert sbtdspsr != null;
        if (sbtdspsr.getXzbh() == null) {
            res = ResultObj.error(ResponseEnum.E_1002.getCode(), "设备所属单位机构编码必填");
            log.error("deviceWritePost  {} : regist remsg...", "设备所属单位机构编码必填");
        } else if (sbtdspsr.getDeviceconfig() == null) {
            res = ResultObj.error(ResponseEnum.E_1002.getCode(), "请impn先配置设备推送配置");
            log.error("deviceWritePost  {} : regist remsg...", "请impn先配置设备推送配置");
        } else {
            res = doDeviceWriteGetResultObj(sbtdspsr);
        }
        if (res.getStatus() == 200) {
            pushdesc = res.getData().toString();
        } else {
            pushdesc = res.getMsg();
            pushstatus = 1;
        }
        //数据库记录操作
        Traffdevicewriteresult traffdevicewriteresult = traffdevicewriteresultMapper.selectOne(TransHelper.transDeviceWriteResult(sbtdspsr));
        if (traffdevicewriteresult == null) {
            traffdevicewriteresultMapper.insertSelective(TransHelper.transDeviceWriteResult(sbtdspsr, pushstatus, pushdesc));
        } else {
            if (traffdevicewriteresult.getPushstatus() == 0) {
                pushstatus = 0;
            }
            traffdevicewriteresultMapper.updateByPrimaryKeySelective(TransHelper.transDeviceWriteResult(sbtdspsr, pushstatus, pushdesc, traffdevicewriteresult.getPushcount() + 1));
        }
        return res;
    }

    public ResultObj registall(HttpServletResponse response) {
        response.setContentType("text/html;charset=utf-8");
        String ret;
        int count, susscee = 0, fail = 0;
        List<SbtdspsrParam> list = sbtdspsrMapper.selectDeviceWrite();
        count = list.size();
        try {
            write(response, "共查询出需要写入的设备" + count + "条");
        } catch (IOException e) {
            log.error("设备批量写入 registall -->>io异常" + e.toString());
        }
        for (SbtdspsrParam val : list) {
            try {
                write(response, "--->>>开始写入第" + (susscee + fail + 1) + "条,剩余" + (count - susscee - fail - 1) + "条。设备编号:" + val.getSbbh() + ",通道编号:" + val.getTdbh() + ",设备名称:" + val.getTdmc());
                ResultObj regest = updateAndRegist(val);
                if (regest.getStatus() == 200) {
                    susscee++;
                    write(response, "<<<---写入成功:" + regest.getData());
                } else {
                    fail++;
                    write(response, "<<<---写入失败:" + regest.getMsg());
                }
            } catch (IOException e) {
                log.error("设备批量写入 registall -->>io异常" + e.toString());
            }
        }
        ret = "查询出需要设备写入的设备数:" + count + "条,其中成功" + susscee + "条，失败" + fail + "条";
        try {
            write(response, ret);
        } catch (IOException e) {
            log.error("设备批量写入 registall -->>io异常" + e.toString());
        }
        return ResultObj.ok(ret);
    }

    public ResultObj update(SbtdspsrParam sbtdspsr) {
        DeviceWriteParam param = TransHelper.transDevice(sbtdspsr, CodeConst.device_update);
        WriteResultObj writeResultObj = new WriteResultObj(); //deviceWritePost(param);
        if (writeResultObj.getStatus() == 200) {
            return ResultObj.ok(writeResultObj.getMessage());
        }
        return ResultObj.error(writeResultObj.getStatus(), writeResultObj.getMessage());
    }

    public ResultObj remove(SbtdspsrParam sbtdspsr) {
        DeviceWriteParam param = TransHelper.transDevice(sbtdspsr, CodeConst.device_remove);
        WriteResultObj writeResultObj = new WriteResultObj(); //deviceWritePost(param);
        if (writeResultObj.getStatus() == 200) {
            return ResultObj.ok(writeResultObj.getMessage());
        }
        return ResultObj.error(writeResultObj.getStatus(), writeResultObj.getMessage());
    }

    public ResultObj report(SbtdspsrParam sbtdspsr) {
        DeviceWriteParam param = TransHelper.transDevice(sbtdspsr, CodeConst.device_report);
        WriteResultObj writeResultObj = new WriteResultObj(); //deviceWritePost(param);
        if (writeResultObj.getStatus() == 200) {
            return ResultObj.ok(writeResultObj.getMessage());
        }
        return ResultObj.error(writeResultObj.getStatus(), writeResultObj.getMessage());
    }

    private WriteResultObj deviceWritePost(DeviceWriteParam param) throws  TimeoutException, InterruptedException,Exception{
        HttpHeaders headers = new HttpHeaders();
        String token = stringRedisTemplate.opsForValue().get(qztoken);
        if (token == null) {
            log.error("deviceWritePost  {} : redis token empty..", qztoken);
            return null;
        }
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        headers.add("token", token);//
        List<DeviceWriteParam> list = new ArrayList<>();
        list.add(param);
        HttpEntity<List<DeviceWriteParam>> requestEntity = new HttpEntity<>(list, headers);
        WriteResultObj writeResultObj = CompletableFuture.supplyAsync(() -> restTemplate.postForObject(devicewriteurl, requestEntity, WriteResultObj.class)).get(timeout, TimeUnit.SECONDS);
        return writeResultObj;
    }

    private ResultObj doDeviceWriteGetResultObj(SbtdspsrParam sbtdspsr) {
        ResultObj res;
        sbtdspsr.setSbcsName(devicesupplier);
        //组装请求数据
        DeviceWriteParam param = TransHelper.transDevice(sbtdspsr, CodeConst.device_regist);
        WriteResultObj writeResultObj;
        try {
            //发送请求返回结果
            writeResultObj = deviceWritePost(param);
            if (writeResultObj == null) {
                writeResultObj = new WriteResultObj(ResponseEnum.E_9999.getCode(), "token凭证获取失败");
            }
        } catch (TimeoutException e) {
            log.error("devicewrite - sendEvent 请求超时:" + e.toString());
            writeResultObj = new WriteResultObj(ResponseEnum.E_1008.getCode(), ResponseEnum.E_1008.getMsg());
        } catch (Exception e) {
            log.error("devicewrite - sendEvent 异常:" + e.toString());
            writeResultObj = new WriteResultObj(ResponseEnum.E_9999.getCode(), e.toString());
        }
        //判断成功还是失败
        if (writeResultObj.getStatus() == 200) {
            res = ResultObj.ok(writeResultObj.getMessage());
            log.info("deviceWritePost  {} : regist remsg...Data=" + param.toString(), writeResultObj.toString());
        } else {
            res = ResultObj.error(writeResultObj.getStatus(), writeResultObj.getMessage());
            log.error("deviceWritePost  {} : regist remsg...Data=" + param.toString(), writeResultObj.toString());
        }
        return res;
    }

    private void write(HttpServletResponse response, String content) throws IOException {
        response.getWriter().write(content + "<br/>");
        response.flushBuffer();
        response.getWriter().flush();
    }

    public ResultObj updateAndRegists(List<SbtdspsrParam> sbtdspsrs) {
        int error = 0;
        int success = 0;
        for (SbtdspsrParam ta : sbtdspsrs) {
            ResultObj resultObj = updateAndRegist(ta);
            boolean successFlag = resultObj.getStatus() == ResponseEnum.SUCCESS.getCode();
            /* 成功 */
            if (successFlag) {
                success++;
                continue;
            }
            error++;
        }
        return ResultObj.error(ResponseEnum.SUCCESS.getCode(), "成功" + success + "条|失败" + error + "条");
    }

}