package com.jsowell.netty.handler;

import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.primitives.Bytes;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.ykc.LoginRequestData;
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.ykc.PileChannelEntity;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.pile.domain.ykcCommond.IssueQRCodeCommand;
import com.jsowell.pile.domain.ykcCommond.ProofreadTimeCommand;
import com.jsowell.netty.factory.YKCOperateFactory;
import com.jsowell.pile.service.YKCPushCommandService;
import com.jsowell.pile.service.IPileBasicInfoService;
import com.jsowell.pile.service.IPileMsgRecordService;
import com.jsowell.pile.vo.base.PileInfoVO;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Component
public class LoginRequestHandler extends AbstractHandler{

	@Autowired
	private IPileBasicInfoService pileBasicInfoService;

    @Autowired
    private YKCPushCommandService ykcPushCommandService;

    @Autowired
    private IPileMsgRecordService pileMsgRecordService;

    @Autowired
    private RedisCache redisCache;

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

	private List<String> newProgramVersionList = Lists.newArrayList("c6-30");

	@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[] pileSnByte = BytesUtil.copyBytes(msgBody, startIndex, length);
		String pileSn = BytesUtil.binary(pileSnByte, 16);
		// log.info("桩号：{}", pileSn);

		// 保存时间
		saveLastTime(pileSn);

        // 桩类型  0 表示直流桩， 1 表示交流桩
        startIndex += length;
        length = 1;
		byte[] pileTypeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String pileType = BytesUtil.bcd2Str(pileTypeByteArr);

		// 充电枪数量
        startIndex += length;
		byte[] connectorNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String connectorNum = BytesUtil.bcd2Str(connectorNumByteArr);

		// 通信协议版本  版本号乘 10，v1.0 表示 0x0A
        startIndex += length;
		byte[] communicationVersionByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		// int i = Integer.parseInt(BytesUtil.bcd2Str(communicationVersionByteArr)); // 0F --> 15
        BigDecimal bigDecimal = new BigDecimal(BytesUtil.bcd2Str(communicationVersionByteArr));
        BigDecimal communicationVersionTemp = bigDecimal.divide(new BigDecimal(10));
        String communicationVersion = "v" + communicationVersionTemp;

		// 程序版本
        startIndex += length;
        length = 8;
		byte[] programVersionByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
        String programVersion = BytesUtil.ascii2Str(programVersionByteArr);
        // log.info("程序版本:{}  length:{}", programVersion, programVersion.length());

		// 网络连接类型  0x00 SIM 卡  0x01 LAN   0x02 WAN  0x03 其他
        startIndex += length;
        length = 1;
		byte[] internetConnectionTypeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
        String internetConnection = BytesUtil.bcd2Str(internetConnectionTypeByteArr);

		// sim卡
        startIndex += length;
        length = 10;
		byte[] simCardNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
		String iccid = BytesUtil.bin2HexStr(simCardNumByteArr);

		// 运营商  0x00 移动  0x02 电信  0x03 联通  0x04 其他
        startIndex += length;
        length = 1;
		byte[] businessTypeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
        String business = BytesUtil.bcd2Str(businessTypeByteArr);

		LoginRequestData loginRequestData = LoginRequestData.builder()
				.pileSn(pileSn)
				.pileType(pileType)
				.connectorNum(connectorNum)
				.communicationVersion(communicationVersion)
				.programVersion(programVersion)
				.internetConnection(internetConnection)
				.iccid(iccid)
				.business(business)
				.build();
        
		// 结果（默认 0x01:登录失败）
		byte[] flag = Constants.oneByteArray;

		// 通过桩编码SN查询数据库，如果有数据，则登录成功，否则登录失败
		PileInfoVO pileInfoVO = null;
		try {
			pileInfoVO = pileBasicInfoService.selectPileInfoBySn(pileSn);
		} catch (Exception e) {
			log.error("selectPileInfoBySn发生异常", e);
		}

		if (pileInfoVO != null) {
			flag = Constants.zeroByteArray;
			// 登录成功，保存桩号和channel的关系
			PileChannelEntity.put(pileSn, channel);
			// 更改桩和该桩下的枪口状态分别为 在线、空闲 公共方法修改状态
			pileBasicInfoService.updateStatus(BytesUtil.bcd2Str(ykcDataProtocol.getFrameType()), pileSn, null, null, null);
			// 充电桩使用的sim卡，把信息存库
			if (StringUtils.equals("00", internetConnection)) {
				try {
					pileBasicInfoService.updatePileSimInfo(pileSn, iccid);
				} catch (Exception e) {
					log.error("更新充电桩sim卡信息失败", e);
				}
			}

			CompletableFuture.runAsync(() -> {
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// 对时
				ProofreadTimeCommand command = ProofreadTimeCommand.builder().pileSn(pileSn).build();
				ykcPushCommandService.pushProofreadTimeCommand(command);
			});

			// log.info("下面进行下发二维码 pileSn:{}, thread:{}", pileSn, Thread.currentThread().getName());
			CompletableFuture.runAsync(() -> {
				try {
					Thread.sleep(600);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// 下发二维码
				IssueQRCodeCommand issueQRCodeCommand = IssueQRCodeCommand.builder().pileSn(pileSn).build();
				ykcPushCommandService.pushIssueQRCodeCommand(issueQRCodeCommand);
			});
		}

		// 保存报文 TODO 没有登录认证通过还要不要保存报文？
		String jsonMsg = JSONObject.toJSONString(loginRequestData);
		pileMsgRecordService.save(pileSn, pileSn, type, jsonMsg, ykcDataProtocol.getHEXString());

		// 消息体
		byte[] messageBody = Bytes.concat(pileSnByte, flag);
		return getResult(ykcDataProtocol, messageBody);
	}
}
