package com.xhpc.evcs.api;

import cn.hutool.core.collection.CollUtil;
import com.xhpc.common.api.PileOrderService;
import com.xhpc.common.core.domain.R;
import com.xhpc.common.core.utils.DateUtils;
import com.xhpc.evcs.domain.AuthSecretToken;
import com.xhpc.evcs.domain.EtOrderMapping;
import com.xhpc.evcs.domain.XhpcChargingStation;
import com.xhpc.evcs.dto.*;
import com.xhpc.evcs.encryption.EvcsConst;
import com.xhpc.evcs.jpa.*;
import com.xhpc.evcs.notification.CoreDispatcher;
import com.xhpc.evcs.notification.NotificationStartChargeResultTask;
import com.xhpc.evcs.utils.JSONUtil;
import com.xhpc.order.domain.XhpcHistoryOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.xhpc.common.data.redis.StaticBeanUtil.REDIS;
import static com.xhpc.common.data.redis.StaticBeanUtil.genOrder;
import static com.xhpc.evcs.domain.AuthSecretToken.SECRET_TOKEN_TYPE_OUT;

@RestController
public class QueryStartChargeController extends CoreDispatcher {

    @Autowired
    AuthSecretTokenRepository authSecretTokenRepository;
    @Autowired
    private OrderMappingRepository etOrderMappingRepo;
    @Autowired
    private XhpcHistoryOrderRepository xhpcHistoryOrderRepository;
    @Autowired
    private XhpcTerminalRepository xhpcTerminalRepository;
    @Autowired
    private PileOrderService pileOrderService;
    @Autowired
    private XhpcInternetUserRepository xhpcInternetUserRepository;
    @Autowired
    private XhpcChargingStationRepository xhpcChargingStationRepository;

    private final Logger logger = LoggerFactory.getLogger(QueryStartChargeController.class);
    private final ExecutorService asyncExecutor = Executors.newFixedThreadPool(40);
    /**
     * 请求启动充电
     * @param commonRequest
     * @return
     * @throws Exception
     */
    @PostMapping(value = "/v1/query_start_charge")
    public CommonResponse queryStartCharge(@RequestBody CommonRequest<StartChargeRequest> commonRequest) throws Exception {

        CommonResponse resp = new CommonResponse();
        resp.setRet(EvcsConst.RET_FAIL);
        Map<String, Object> pushOrder = new HashMap<>();
        String orderNo ="";
        StartChargeRequest startChargeRequest = JSONUtil.readParams(commonRequest.getData(), StartChargeRequest.class);
        if (startChargeRequest == null) {
            resp.setMsg("Request or token params validation failed");
        } else {
            String startChargeSeq = startChargeRequest.getStartChargeSeq();
            EtOrderMapping orderMapping = etOrderMappingRepo.findByEvcsOrderNo(startChargeSeq).orElse(null);
            if (orderMapping != null) {
                resp.setMsg("Duplicated StartChargeSeq");
            } else {
                StartChargeResponse startChargeResponse = new StartChargeResponse();
                startChargeResponse.setFailReason(0);
                startChargeResponse.setSuccStat(1);
                startChargeResponse.setStartChargeSeqStat(4);
                String connectorId = startChargeRequest.getConnectorId();
                Map<String, Object> cacheGun = REDIS.getCacheMap("gun:".concat(connectorId));
                String terminalStatus = (String) cacheGun.get("vehicleGunStatus");
                String status = (String) cacheGun.get("status");
                EtOrderMapping etOrderMapping = new EtOrderMapping();
                Date now = DateUtils.getNowDate();
                etOrderMapping.setCreateTime(now);
                etOrderMapping.setEvcsOrderNo(startChargeSeq);
                if (!"空闲".equals(status)) {
                    resp.setMsg("终端状态异常:[".concat(status == null ? "未注册" : status).concat("]"));
                    emptyHorder(startChargeSeq, connectorId, etOrderMapping);
                } else if ("否".equals(terminalStatus)) {
                    resp.setMsg("未插枪");
                    emptyHorder(startChargeSeq, connectorId, etOrderMapping);
                } else {
                    String plateNum = startChargeRequest.getPlateNum();
                    plateNum = plateNum == null ? startChargeRequest.getPlateNum2() : plateNum;
                    R res = pileOrderService.pileStartUpBy3rd(startChargeSeq, startChargeRequest.getDriverId(),
                            startChargeRequest.getChargingAmt(), plateNum, -1, connectorId);
                    startChargeResponse.setStartChargeSeq(startChargeSeq);
                    startChargeResponse.setConnectorID(connectorId);
                    resp.setMsg(res.getMsg());
                    if (res.getCode() != 200) {
                        if (res.getCode() != 500) {
                            startChargeResponse.setFailReason(res.getCode());
                        } else {
                            startChargeResponse.setFailReason(3);
                        }
                        startChargeResponse.setSuccStat(1);
                        startChargeResponse.setStartChargeSeqStat(4);
                        emptyHorder(startChargeSeq, connectorId, etOrderMapping);
                    } else {
                        Map<String, Object> etOrderData = (Map<String, Object>) res.getData();
                        if (etOrderData != null) {
                            resp.setRet(EvcsConst.RET_SUCC);
                            startChargeResponse.setStartChargeSeqStat(1);
                            startChargeResponse.setSuccStat(0);
                            startChargeResponse.setFailReason(0);

                            pushOrder.put("startChargeSeqStat", 1);
                            pushOrder.put("internetSerialNumber", startChargeRequest.getStartChargeSeq());
                            pushOrder.put("connectorID", connectorId);
                            pushOrder.put("startChargeNotificationStat", 0);
                            pushOrder.put("chargeOrderInfoNotificationStat", 0);
                            pushOrder.put("operatorId3rdpty", startChargeSeq.substring(0, 9));
                            pushOrder.put("startTime", etOrderData.get("startTime"));
                            orderNo = (String) etOrderData.get("orderNo");
                            etOrderMapping.setXhOrderNo(orderNo);
                            REDIS.setCacheMap("pushOrder:".concat(orderNo), pushOrder);
                        } else {
                            emptyHorder(startChargeSeq, connectorId, etOrderMapping);
                        }
                    }
                }
                etOrderMappingRepo.save(etOrderMapping);
                resp.setData(JSONUtil.toJSONString(startChargeResponse));
            }
        }

//        if("0".equals(resp.getRet())){
//            String finalOrderNo = orderNo;
//            CompletableFuture.runAsync(()->{
//                System.out.println(">>> 异步回复 <<<");
//                processRequest(pushOrder,startChargeRequest.getStartChargeSeq(), finalOrderNo);
//            },asyncExecutor);
//        }
//        System.out.println(">>> 回复启动结果 <<<");
        return resp;
    }

    private void emptyHorder(String startChargeSeq, String connectorId, EtOrderMapping etOrderMapping) {

        final Long stationId = REDIS.getCacheMapValue("pile:".concat(connectorId.substring(0, 14)), "stationId");
        XhpcChargingStation xhpcChargingStation = xhpcChargingStationRepository.findById(stationId).orElse(null);
        if (xhpcChargingStation != null) {
            XhpcHistoryOrder emptyHorder = new XhpcHistoryOrder();
            emptyHorder.setTenantId(xhpcChargingStation.getTenantId());
            Date now = DateUtils.getNowDate();
            emptyHorder.setStartTime(now);
            emptyHorder.setEndTime(now);
            emptyHorder.setCreateTime(now);
            emptyHorder.setUpdateTime(now);
            emptyHorder.setStopReasonEvcs("平台停止");
            String sn = genOrder(connectorId);
            etOrderMapping.setXhOrderNo(sn);
            emptyHorder.setSerialNumber(sn);
            emptyHorder.setInternetSerialNumber(startChargeSeq);
            String operatorId3rdpty = startChargeSeq.substring(0, 9);
            emptyHorder.setOperatorId3rdptyEvcs(operatorId3rdpty);
            emptyHorder.setUserId(xhpcInternetUserRepository.queryDbId(operatorId3rdpty));
            emptyHorder.setType(1);
            emptyHorder.setSource(1);
            emptyHorder.setState(-1);
            emptyHorder.setChargingStationId(stationId);
            emptyHorder.setTerminalId(xhpcTerminalRepository.queryDbId(connectorId));
            emptyHorder.setConfirmResult(-1);
            xhpcHistoryOrderRepository.save(emptyHorder);
        }
    }


    public void notify(NotificationStartChargeResultRequestData notificationStartChargeResultRequestData,
                       AuthSecretToken authSecretTokenOut, String orderNo, String startChargeSeq) throws IOException {

        String data = JSONUtil.toJSONString(notificationStartChargeResultRequestData);

        CommonRequest<NotificationStartChargeResultRequestData> commonRequest = new CommonRequest<>();
        commonRequest.setData(data);
        String responseBody = ok(commonRequest, "/notification_start_charge_result", authSecretTokenOut);
        logger.info("==========第三方调用启动充电接口=====启动推送结果=====responseBody======================="+responseBody+"=================orderNo================="+orderNo);
        NotificationStartStopChargeResultResponse notificationStartStopChargeResultResponse =DTOJsonHelper.parseResponseData(responseBody,NotificationStartStopChargeResultResponse.class, authSecretTokenOut);

        if (null != notificationStartStopChargeResultResponse) {
            //Ensuring that only when startChargeNotificationStat equals 1 won't be notified.
            if (notificationStartStopChargeResultResponse.getSuccStat() == 0) {
                REDIS.setCacheMapValue("pushOrder:".concat(orderNo), "startChargeNotificationStat", 1);
            } else {
                Integer startChargeNotificationStat = REDIS.getCacheMapValue("pushOrder:".concat(orderNo),
                        "startChargeNotificationStat");
                if (startChargeNotificationStat == 0) {
                    startChargeNotificationStat = 2;
                } else {
                    ++startChargeNotificationStat;
                }
                REDIS.setCacheMapValue("pushOrder:".concat(orderNo), "startChargeNotificationStat",startChargeNotificationStat);
                throw new RuntimeException(String.format("push CD start charge order status [%s] failed: %s",notificationStartChargeResultRequestData.getStartChargeSeq(), responseBody));
            }
        }
    }
    @Async
    public void processRequest(Map<String, Object> pushOrder,String startChargeSeq,String orderNo){
        System.out.println(">>> 开始执行后续操作 <<<");
        try{
            //推送启动成功数据
            String operatorId = startChargeSeq.substring(0, 9);
            Optional<AuthSecretToken> authSecretToken =authSecretTokenRepository.findByOperatorId3irdptyAndSecretTokenType(operatorId,SECRET_TOKEN_TYPE_OUT);
            if (authSecretToken.isPresent()) {
                NotificationStartChargeResultRequestData notificationStartChargeResultRequestData = new NotificationStartChargeResultRequestData();
                notificationStartChargeResultRequestData.setStartTime((String) pushOrder.get("startTime"));
                notificationStartChargeResultRequestData.setStartChargeSeq(startChargeSeq);
                notificationStartChargeResultRequestData.setConnectorId((String) pushOrder.get("connectorID"));
                notificationStartChargeResultRequestData.setStartChargeSeqStat((Integer) pushOrder.get("startChargeSeqStat"));
                notify(notificationStartChargeResultRequestData, authSecretToken.get(), orderNo,startChargeSeq);
            }
        }catch (Exception e){
            logger.info("==========第三方调用启动充电接口=====启动推送失败=====responseBody=======================");
        }
    }
}
