package com.jsowell.netty.handler;

import com.alibaba.fastjson2.JSONObject;
import com.google.common.primitives.Bytes;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.ykc.YKCDataProtocol;
import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode;
import com.jsowell.common.enums.ykc.CardStatusEnum;
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
import com.jsowell.common.enums.ykc.StartModeEnum;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.netty.factory.YKCOperateFactory;
import com.jsowell.pile.domain.MemberBasicInfo;
import com.jsowell.pile.domain.MemberPlateNumberRelation;
import com.jsowell.pile.domain.PileAuthCard;
import com.jsowell.pile.dto.GenerateOrderDTO;
import com.jsowell.pile.service.*;
import com.jsowell.pile.vo.CarVinInfoVO;
import com.jsowell.pile.vo.uniapp.MemberVO;
import com.jsowell.pile.vo.uniapp.PersonalPileInfoVO;
import com.jsowell.wxpay.dto.WechatSendMsgDTO;
import com.jsowell.wxpay.service.WxAppletRemoteService;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * 充电桩主动申请启动充电  0x31
 *
 * 启动充电鉴权结果
 * @author JS-ZZA
 * @date 2022/9/19 14:29
 */
@Slf4j
@Component
public class ConfirmStartChargingRequestHandler extends AbstractHandler{
    private final String type = YKCUtils.frameType2Str(YKCFrameTypeCode.REQUEST_START_CHARGING_CODE.getBytes());

    @Autowired
    private IPileAuthCardService pileAuthCardService;

    @Autowired
    private IOrderBasicInfoService orderBasicInfoService;

    @Autowired
    private ICarVinInfoService carVinInfoService;

    @Autowired
    private IMemberPlateNumberRelationService memberPlateNumberRelationService;

    @Autowired
    private WxAppletRemoteService wxAppletRemoteService;

    @Autowired
    private IMemberBasicInfoService memberBasicInfoService;

    @Override
    public void afterPropertiesSet() throws Exception {
        YKCOperateFactory.register(type, this);
    }

    @Override
    public byte[] supplyProcess(YKCDataProtocol ykcDataProtocol, Channel channel) {
        log.info("[===充电桩主动申请启动充电===] param:{}, channel:{}", JSONObject.toJSONString(ykcDataProtocol), channel.toString());
        // 获取消息体
        byte[] msgBody = ykcDataProtocol.getMsgBody();

        int startIndex = 0;
        int length = 7;

        // 桩编码
        byte[] pileSnByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
        String pileSn = BytesUtil.binary(pileSnByteArr, 16);

        // 保存时间
        saveLastTime(pileSn);

        // 枪号
        startIndex += length;
        length = 1;
        byte[] connectorNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
        String connectorCode = BytesUtil.bcd2Str(connectorNumByteArr);

        // 启动方式
        // 0x01 表示通过刷卡启动充电
        // 0x02 表求通过帐号启动充电 （暂不支持）
        // 0x03 表示vin码启动充电
        startIndex += length;
        byte[] startModeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
        String startMode = BytesUtil.bcd2Str(startModeByteArr);

        // 是否需要密码  0x00 不需要 0x01 需要
        startIndex += length;
        byte[] needPasswordFlagByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
        String needPasswordFlag = BytesUtil.bcd2Str(needPasswordFlagByteArr);

        // 物理卡号  不足 8 位补 0
        startIndex += length;
        length = 8;
        byte[] cardNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
        String physicsCard = BytesUtil.binary(cardNumByteArr, 16);
        log.info("桩号:{}申请充电物理卡号:{}", pileSn, physicsCard);

        // 输入密码  对用户输入的密码进行16 位MD5 加密，采用小写上传
        startIndex += length;
        length = 16;
        byte[] inputPasswordByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);

        // VIN码
        startIndex += length;
        length = 17;
        byte[] vinCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
        String vinCode = BytesUtil.ascii2Str(vinCodeByteArr);
        log.info("桩号:{}申请充电VIN码:{}", pileSn, vinCode);

        /**
         * 刷卡启动充电
         */
        String logicCard = "";
        byte[] authenticationFlagByteArr = Constants.zeroByteArray; // 鉴权成功标识
        byte[] accountBalanceByteArr = Constants.zeroByteArray; // 账户余额
        String transactionCode = "";
        try {
            if (StringUtils.equals("01", startMode)) {
                // 查询卡信息 根据传过来的物理卡号查询数据库中此卡信息
                PileAuthCard pileAuthCardInfo = pileAuthCardService.selectCardInfoByLogicCard(physicsCard);
                if (pileAuthCardInfo == null) {
                    // 未查到此卡信息
                    throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_HAS_NO_INFO);
                }
                if (StringUtils.isBlank(pileAuthCardInfo.getMemberId())) {
                    // 卡未绑定用户
                    throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_NOT_BIND_USER);
                }
                // 判断卡状态
                if (!StringUtils.equals(CardStatusEnum.NORMAL.getCode(), pileAuthCardInfo.getStatus())) {
                    return null;
                }

                // 刷卡生成订单 刷卡启动充电
                GenerateOrderDTO dto = new GenerateOrderDTO();
                dto.setPileAuthCardInfo(pileAuthCardInfo);
                dto.setPileSn(pileSn);
                dto.setConnectorCode(connectorCode);
                dto.setStartMode(StartModeEnum.AUTH_CARD.getValue());
                Map<String, Object> map = orderBasicInfoService.generateOrderByCard(dto);
                if (map != null) {
                    transactionCode = (String) map.get("transactionCode");
                    accountBalanceByteArr = YKCUtils.getPriceByte(String.valueOf(map.get("accountBalance")), 2);
                    // 鉴权成功标识  0x00 失败 0x01 成功
                    authenticationFlagByteArr = Constants.oneByteArray;

                    // 推送小程序启动充电消息
                    // 通过memberId查询openId
                    MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMemberId(pileAuthCardInfo.getMemberId());
                    WechatSendMsgDTO sendMsgDTO = new WechatSendMsgDTO();
                    sendMsgDTO.setOpenId(memberBasicInfo.getOpenId());
                    sendMsgDTO.setOrderCode((String) map.get("orderCode"));

                    wxAppletRemoteService.startChargingSendMsg(sendMsgDTO);
                }else {
                    throw new BusinessException("", "生成刷卡订单失败");
                }
            }
        } catch (BusinessException e){
            transactionCode = "00000000000000000000000000000000";
            accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8);
            authenticationFlagByteArr = Constants.zeroByteArray;

            log.error("刷卡启动充电鉴权 error:{}, {}", e.getCode(), e.getMessage());
        }catch (Exception e){
            transactionCode = "00000000000000000000000000000000";
            accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8);
            authenticationFlagByteArr = Constants.zeroByteArray;

            log.error("刷卡启动充电鉴权 error", e);

        }

        try {
            /**
             * VIN码启动充电
             */
            if (StringUtils.equals("03", startMode)) {
                // 通过vin码查询数据库绑定用户信息
                MemberPlateNumberRelation plateInfo = memberPlateNumberRelationService.getMemberPlateInfoByVinCode(vinCode);
                if (plateInfo == null) {
                    throw new BusinessException("", "未查到绑定用户信息");
                }
                if (!StringUtils.equals("1", plateInfo.getVinStatus())) {
                    // 1- 正常使用
                    throw new BusinessException("", "vin状态不正确");
                }
                // vin码生成订单 vin启动充电
                GenerateOrderDTO dto = new GenerateOrderDTO();
                dto.setMemberPlateNumberRelation(plateInfo);
                dto.setPileSn(pileSn);
                dto.setConnectorCode(connectorCode);
                dto.setStartMode(StartModeEnum.VIN_CODE.getValue());
                Map<String, Object> map = orderBasicInfoService.generateOrderByCard(dto);
                if (map != null) {
                    transactionCode = (String) map.get("transactionCode");
                    accountBalanceByteArr = YKCUtils.getPriceByte(String.valueOf(map.get("accountBalance")), 2);
                    // 鉴权成功标识  0x00 失败 0x01 成功
                    authenticationFlagByteArr = Constants.oneByteArray;

                    // 推送小程序启动充电消息
                    // 通过memberId查询openId
                    MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMemberId(plateInfo.getMemberId());
                    WechatSendMsgDTO sendMsgDTO = new WechatSendMsgDTO();
                    sendMsgDTO.setOpenId(memberBasicInfo.getOpenId());
                    sendMsgDTO.setOrderCode((String) map.get("orderCode"));

                    wxAppletRemoteService.startChargingSendMsg(sendMsgDTO);
                }else {
                    throw new BusinessException("", "生成vin订单失败");
                }
            }
        }catch (BusinessException e){
            transactionCode = "00000000000000000000000000000000";
            accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8);
            authenticationFlagByteArr = Constants.zeroByteArray;

            log.error("VIN码启动充电鉴权 error:{}, {}", e.getCode(), e.getMessage());
        }catch (Exception e) {
            transactionCode = "00000000000000000000000000000000";
            accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8);
            authenticationFlagByteArr = Constants.zeroByteArray;

            log.error("VIN码启动充电鉴权 error", e);
        }

        // 应答
        // 交易流水号
        // String transactionCode = IdUtils.generateTransactionCode(pileSn, connectorCode);
        byte[] serialNumByteArr = BytesUtil.str2Bcd(transactionCode);

        // 逻辑卡号
        // String logicCardNum = "00000000";

        // 账户余额  保留两位小数
        // MemberVO memberVO = memberBasicInfoService.selectInfoByPhysicsCard(physicsCard);
        // BigDecimal principalBalance = memberVO.getPrincipalBalance(); // 本金金额
        // double accountBalance = principalBalance.add(memberVO.getGiftBalance()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        // byte[] accountBalanceByteArr = BytesUtil.str2Bcd(String.valueOf(accountBalance));

        // 鉴权成功标识  0x00 失败 0x01 成功
        // byte[] authenticationFlagByteArr = Constants.oneByteArray;

        /**
         * 失败原因
         * 0x01 账户不存在
         * 0x02 账户冻结
         * 0x03 账户余额不足
         * 0x04 该卡存在未结账记录
         * 0x05 桩停用
         * 0x06 该账户不能在此桩上充电
         * 0x07 密码错误
         * 0x08 电站电容不足
         * 0x09 系统中vin 码不存在
         * 0x0A 该桩存在未结账记录
         * 0x0B 该桩不支持刷卡
         */
        byte[] defeatReasonByteArr = Constants.zeroByteArray;

        // 不足位数的值补零
        // cardNumByteArr = BytesUtil.checkLengthAndBehindAppendZero(cardNumByteArr, 16);
        // serialNumByteArr = BytesUtil.checkLengthAndBehindAppendZero(serialNumByteArr, 32);
        // pileSnByteArr = BytesUtil.checkLengthAndBehindAppendZero(pileSnByteArr, 14);
        // accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8);

        // 拼装消息体
        byte[] msgBodyByteArr = Bytes.concat(serialNumByteArr, pileSnByteArr, connectorNumByteArr, cardNumByteArr, accountBalanceByteArr,
                authenticationFlagByteArr, defeatReasonByteArr);

        return getResult(ykcDataProtocol, msgBodyByteArr);

    }
}
