package com.jsowell.netty.handler;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.core.domain.ykc.GroundLockData;
import com.jsowell.common.core.domain.ykc.YKCDataProtocol;
import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.uniapp.OccupyOrderPayStatusEnum;
import com.jsowell.common.enums.uniapp.OccupyOrderStatusEnum;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.netty.factory.YKCOperateFactory;
import com.jsowell.pile.domain.OrderPileOccupy;
import com.jsowell.pile.service.OrderPileOccupyService;
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.Locale;
import java.util.Objects;

/**
 * 地锁数据上送
 *
 * 地锁状态/报警信息变化时，桩立刻上送变位/报警信息；地锁状态不变化时，每隔 5 分钟周期 性上送地锁状态。若无报警信息，不上送。
 *
 * @author JS-ZZA
 * @date 2022/9/19 15:21
 */
@Slf4j
@Component
public class GroundLockDataUploadHandler extends AbstractHandler{
    @Autowired
    private RedisCache redisCache;

    @Autowired
    private OrderPileOccupyService orderPileOccupyService;

    private final String type = YKCUtils.frameType2Str(YKCFrameTypeCode.GROUND_LOCK_DATA_UPLOAD_CODE.getBytes());

    @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();

        // 桩编码
        byte[] pileSnByteArr = BytesUtil.copyBytes(msgBody, 0, 7);
        String pileSn = BytesUtil.bcd2Str(pileSnByteArr);

        // 枪号
        byte[] connectorCodeByteArr = BytesUtil.copyBytes(msgBody, 7, 1);
        String connectorCode = BytesUtil.bcd2Str(connectorCodeByteArr);

        /**
         * 车位锁状态
         * 0x00：未到位状态
         * 0x55：升锁到位状态
         * 0xFF：降锁到位状态
         */
        byte[] parkingLockStatusByteArr = BytesUtil.copyBytes(msgBody, 8, 1);
        // String parkingLockStatus = BytesUtil.bcd2Str(parkingLockStatusByteArr);
        String parkingLockStatus = BytesUtil.bin2HexStr(parkingLockStatusByteArr).toUpperCase(Locale.ROOT);

        // 车位状态  0x00：无车辆 0xFF：停放车辆
        byte[] parkingStatusByteArr = BytesUtil.copyBytes(msgBody, 9, 1);
        // String parkingStatus = BytesUtil.bcd2Str(parkingStatusByteArr);
        String parkingStatus = BytesUtil.bin2HexStr(parkingStatusByteArr).toUpperCase(Locale.ROOT);

        // 地锁电量状态  百分比值0~100
        byte[] groundLockElectricByteArr = BytesUtil.copyBytes(msgBody, 10, 1);
        String groundLockElectric = BytesUtil.bcd2Str(groundLockElectricByteArr);

        // 报警状态   0x00：正常无报警  0xFF：待机状态摇臂破坏  0x55：摇臂升降异常(未到位)
        byte[] alarmStatusByteArr = BytesUtil.copyBytes(msgBody, 11, 1);
        // String alarmStatus = BytesUtil.bcd2Str(alarmStatusByteArr);
        String alarmStatus = BytesUtil.bin2HexStr(alarmStatusByteArr).toUpperCase(Locale.ROOT);

        // 预留位  全部置0
        byte[] waitingUseByteArr = BytesUtil.copyBytes(msgBody, 12, 4);
        String waitingUse = BytesUtil.bcd2Str(waitingUseByteArr);

        if (StringUtils.equals(parkingLockStatus, "55")) {
            log.info("0x61地锁数据，车位锁状态:升锁到位状态");
            if (StringUtils.equals(parkingStatus, "00")) {
                log.info("0x61地锁数据，车位锁状态: 升锁到位状态, 车位状态: 无车辆");
                raiseTheGroundLock(pileSn, connectorCode);
            } else {
                log.info("0x61地锁数据，车位锁状态: 升锁到位状态, 车位状态: 停放车辆");
            }
        } else if (StringUtils.equals(parkingLockStatus, "FF")) {
            log.info("0x61地锁数据，车位锁状态:降锁到位状态");
            if (StringUtils.equals(parkingStatus, "00")) {
                log.info("0x61地锁数据，车位锁状态: 降锁到位状态, 车位状态: 无车辆");
            } else {
                log.info("0x61地锁数据，车位锁状态: 降锁到位状态, 车位状态: 停放车辆");
                lowerTheGroundLock(pileSn, connectorCode);
            }
        } else {
            log.info("0x61地锁数据，车位锁状态:未到位状态");
        }

        // 封装到对象中
        GroundLockData data = GroundLockData.builder()
                .pileSn(pileSn)
                .connectorCode(connectorCode)
                .parkingLockStatus(parkingLockStatus)
                .parkingStatus(parkingStatus)
                .groundLockElectric(groundLockElectric)
                .alarmStatus(alarmStatus)
                .time(DateUtils.getTime())
                .build();

        // 地锁信息放缓存中 缓存10分钟
        String redisKey = CacheConstants.GROUND_LOCK_DATA + pileSn + connectorCode;
        redisCache.setCacheObject(redisKey, data, CacheConstants.cache_expire_time_10m);

        log.info("[===地锁数据上送===] result: 桩编码:{}, 枪号:{}, 车位锁状态:{}, 车位状态:{}, 地锁电量状态:{}, 报警状态:{}",
                pileSn, connectorCode, parkingLockStatus, parkingStatus, groundLockElectric, alarmStatus);
        return null;
    }

    /**
     * 降锁成功的时候调用
     */
    private void lowerTheGroundLock(String pileSn, String connectorCode) {
        // 查出草稿单占桩订单，将开始时间set进订单信息
        OrderPileOccupy orderInfo = orderPileOccupyService.getDraftOccupyOrder(pileSn, connectorCode);
        if (orderInfo == null) {
            return;
        }
        if (Objects.isNull(orderInfo.getStartTime())) {
            orderInfo.setStatus(OccupyOrderStatusEnum.OCCUPIED.getCode());
            orderInfo.setStartTime(DateUtils.getNowDate());
            orderInfo.setPayStatus(OccupyOrderPayStatusEnum.UN_PAY.getCode());
            // 修改数据库
            log.info("降锁成功，修改订单状态:{}", JSON.toJSONString(orderInfo));
            orderPileOccupyService.updateByPrimaryKeySelective(orderInfo);
        }
    }

    /**
     * 升锁成功时调用
     */
    private void raiseTheGroundLock(String pileSn, String connectorCode) {
        // 两种情况  1是没有停车，地锁自动升起；2是停车完成地锁升起
        boolean stopCarFlag = true;

        // 获取现在缓存中的状态
        String redisKey = CacheConstants.GROUND_LOCK_DATA + pileSn + connectorCode;
        GroundLockData data = redisCache.getCacheObject(redisKey);
        if (data != null) {
            String parkingStatus = data.getParkingStatus();
            if (StringUtils.equals(parkingStatus, "00")) {
                // 无车辆
                stopCarFlag = false;
            }
        }

        if (stopCarFlag) {
            // 停止占桩订单计时
            orderPileOccupyService.stopOccupyPileOrder(pileSn, connectorCode);
        } else {
            // 关闭占桩订单
            orderPileOccupyService.closeOccupyPileOrder(pileSn, connectorCode);
        }
    }
}
