package com.xhpc.pp.logic;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xhpc.common.api.CardService;
import com.xhpc.common.core.domain.R;
import com.xhpc.common.data.up.PileStartChargingData;
import com.xhpc.common.domain.IccardInfo;
import com.xhpc.common.domain.IccardInfoExample;
import com.xhpc.common.enums.StationDeviceEnum;
import com.xhpc.pp.domain.XhpcDeviceMessage;
import com.xhpc.pp.mapper.IccardInfoMapper;
import com.xhpc.pp.mapper.XhpcDeviceMessageMapper;
import com.xhpc.pp.tx.ServiceParameter;
import com.xhpc.pp.tx.ServiceResult;
import com.xhpc.pp.tx.logic.ServiceLogic;
import com.xhpc.pp.utils.HexUtils;
import com.xhpc.pp.utils.security.CRCCalculator;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.xhpc.common.core.constant.Constants.INVALID_OPERATOR;
import static com.xhpc.common.data.redis.StaticBeanUtil.REDIS;
import static com.xhpc.common.data.redis.StaticBeanUtil.seqHex;

@Lazy
@Component("PileStartChargingDataLogic")
public class PileStartChargingDataLogic implements ServiceLogic {

    private static final Logger log = LoggerFactory.getLogger(PileStartChargingDataLogic.class);

    @Resource
    private XhpcDeviceMessageMapper deviceMessageMapper;
    @Resource
    private IccardInfoMapper iccardInfoMapper;
    @Resource
    private CardService cardService;

    @Override
    public ServiceResult service(ServiceParameter sp) throws Exception {

        String resultStr = "00";
        String result = ServiceResult.HEX_00;
        Map<String, Object> req = sp.getParameters();
        ObjectMapper objectMapper = new ObjectMapper();
        PileStartChargingData pileStartChargingData = objectMapper.convertValue(req, PileStartChargingData.class);
        String connectorId = pileStartChargingData.getPileNo().concat(pileStartChargingData.getGunId());
        //todo 桩停用
        String accountOrCardNo = pileStartChargingData.getAccountOrCardNo();
        String corpNo = connectorId.substring(0, 6);
        String balance = "00000000";
        String cardNo = "0000000000000000";
        String orderNo = "00000000000000000000000000000000";
        if (pileStartChargingData.getStartType().equals("01")) { //刷卡启动
            IccardInfoExample example = new IccardInfoExample();
            IccardInfoExample.Criteria criteria = example.createCriteria();
            String physicCardNo;
            if (accountOrCardNo.startsWith("00000000")) {
                physicCardNo = accountOrCardNo.substring(8);
            } else if (accountOrCardNo.endsWith("00000000")) {
                physicCardNo = accountOrCardNo.substring(0, 8);
            } else {
                physicCardNo = accountOrCardNo;
            }
            criteria.andCardidEqualTo(physicCardNo);//.andCorpnoEqualTo(corpNo); // todo remove corpNo alrity
            List<IccardInfo> iccardInfos = iccardInfoMapper.selectByExample(example);
            if (iccardInfos.size() == 1) {
                IccardInfo iccardInfo = iccardInfos.get(0);
                if (iccardInfo.getCardtype() == 0) {
                    resultStr = INVALID_OPERATOR;
                } else {
                    // 调用订单接口
                    cardNo = iccardInfo.getCardno();
                    Integer rateModelId = pileStartChargingData.getRateModelId(); // todo not very strict.
                    if (rateModelId == null)
                        rateModelId = ((Long) REDIS.getCacheMapValue("pile:".concat(connectorId.substring(0, 14)),
                                "rateModelId")).intValue();
                    R r = cardService.cardStartup(cardNo, connectorId, rateModelId.toString());
                    if (r.getCode() == 200) {
                        result = ServiceResult.HEX_01;
                        Map data = (Map) r.getData();
                        orderNo = (String) data.get("serialNumber");
                        Double dBalance = (Double) data.get("balance");
                        dBalance = dBalance * 100;
                        balance = HexUtils.toHexInt(dBalance.longValue());
                        Map<String, Object> cacheOrder = new HashMap<>();
                        String pileNo = connectorId.substring(0, 14);
                        String pkey = "pile:".concat(pileNo);
                        Long pileRateModelId = REDIS.getCacheMapValue(pkey, "rateModelId");
                        cacheOrder.put("pileRateModelId", pileRateModelId);
                        cacheOrder.put("rateModelId", rateModelId);
                        cacheOrder.put("pileNo", pileNo);
                        cacheOrder.put("initBalance", dBalance.intValue() * 100);
                        cacheOrder.put("logicCardNo", cardNo);
                        cacheOrder.put("physicCardNo", accountOrCardNo);
                        cacheOrder.put("gunId", connectorId);
                        cacheOrder.put("startTime",
                                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()).format(Instant.now()));
                        String orderkey = "order:".concat(orderNo);
                        REDIS.setCacheMap(orderkey, cacheOrder);
                        REDIS.setCacheMapValue("gun:".concat(connectorId), "ac.on", false);
                        resultStr = "00";
                    } else {
                        String internalError = r.getMsg();
                        if (internalError.startsWith("0") || internalError.startsWith("1")) {
                            resultStr = internalError;
                        } else {
                            resultStr = "1C";
                            log.error("pile start charging internalError: {}", internalError);
                        }
                    }
                    cardNo = StringUtils.leftPad(iccardInfo.getCardno(), 16, "0");
                }
            } else {
                resultStr = "01";
            }
        }
        String skey = "gun:".concat(connectorId).concat(".seqhex");
        String hex =
                "682A".concat(seqHex(skey)).concat("0032").concat(orderNo).concat(connectorId).concat(cardNo).concat(balance).concat(result).concat(resultStr);
        hex = hex.concat(CRCCalculator.calcCrc(hex));
        String remark = "充电桩发起充电";
        XhpcDeviceMessage deviceMessage = new XhpcDeviceMessage();
        deviceMessage.setType(StationDeviceEnum.PILE.getCode());
        deviceMessage.setSerialNumber(connectorId);
        deviceMessage.setRemark(remark);
        deviceMessage.setStatus(0);
        deviceMessage.setContent((String) req.get("hex"));
        deviceMessageMapper.insertByDomain(deviceMessage);
        return new ServiceResult(HexUtils.toBytes(hex), result);
    }

}
