package org.wcs.business.etag;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.wcs.business.pub.ReportStandard;
import org.wcs.business.redis.EtagRedis;
import org.wcs.config.EtagConfig;
import org.wcs.constant.ConstantData;
import org.wcs.constant.enums.database.ETagTypeEnum;
import org.wcs.constant.enums.database.EtagBusinessTypeEnum;
import org.wcs.constant.enums.database.EtagTaskStatusEnum;
import org.wcs.constant.enums.etag.EtagSubCommandEnum;
import org.wcs.constant.enums.etag.LedBlinkingEnum;
import org.wcs.constant.enums.etag.LedColorEnum;
import org.wcs.mapper.intf.AppEtagTagInfoService;
import org.wcs.mapper.intf.AppEtagTaskService;
import org.wcs.model.bo.etag.EtagLightParams;
import org.wcs.model.bo.etag.EtagReturnInfo;
import org.wcs.model.bo.tuple.Tuple2;
import org.wcs.model.po.app.AppEtagTagInfo;
import org.wcs.model.po.app.AppEtagTask;
import org.wcs.plugin.tcp.model.SocketDataItem;
import org.wcs.utils.AppStringUtils;
import org.wcs.utils.AppThreadUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
 * 电子标签数据处理类
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class EtagDataHandler {

    // 电子标签操作类
    private final EtagAtopOperation etagAtopOperation;
    // 电子标签 redis 操作类
    private final EtagRedis etagRedis;
    // 电子标签操作类
    private final EtagConfig etagConfig;
    // 电子标签信息服务类
    private final AppEtagTagInfoService etagInfoService;
    // 电子标签任务服务类
    private final AppEtagTaskService etagTaskService;

    /**
     * 接收字节数据并解析，主要是解析电子标签扫码器扫描的数据和标签按下确认的数据
     * @param socketDataItem Socket 数据项
     * @param bytes 字节数据
     * @remark 此为参照供应商C#版本的程序的数据解析方法所写，看不懂请不要问我，谢谢
     */
    public void receiveBytes(SocketDataItem socketDataItem, byte[] bytes) {
        AppThreadUtils.startNewThread(() -> {
            EtagReturnInfo etagReturnInfo = new EtagReturnInfo();
            etagReturnInfo.setControllerId(socketDataItem.getSocketId());
            etagReturnInfo.setIp(socketDataItem.getSocketIp());
            etagReturnInfo.setEtagPort(bytes[2] == 0x60 ? 1 : 2);
            etagReturnInfo.setSubCommand((int)bytes[6]);
            etagReturnInfo.setTagId(bytes.length > 7 ? (int)bytes[7] : 0);
            if(etagReturnInfo.getSubCommand() == 6 || etagReturnInfo.getSubCommand() == 7) {
                StringBuilder returnData = new StringBuilder();
                for(int i = 8; i < bytes.length; i++) {
                    if (bytes[i] > 0) {
                        returnData.append((char) bytes[i]);
                    }
                }
                etagReturnInfo.setData(returnData.toString().replaceAll("\\W", ""));
            }
            if(etagReturnInfo.getSubCommand() == 9) {
                byte[] ccb_data = new byte[250];
                for (int k = 8; k < bytes.length && k < 258; k++) {
                    ccb_data[k - 8] = bytes[k];
                }
                int tmp = 0;
                int mixId = 0;
                StringBuilder tagStr = new StringBuilder();
                for(int i = 0; i <= 250; i++) {
                    if ((i - 1) % 8 == 0) {
                        tmp = ccb_data[3 + (i - 1) / 8];
                    }
                    if (tmp % 2 != 1) {
                        mixId = i;
                        tagStr.append("1");
                    } else {
                        tagStr.append("0");
                    }
                    tmp /= 2;
                }
                etagReturnInfo.setData(tagStr.substring(0, mixId).replaceAll("\\W", ""));
            }
            try {
                etagDataHandler(etagReturnInfo); // 数据处理
            } catch (Exception e) {
                log.error("电子标签 {} 收到信息：{}, 数据处理异常：{}", etagReturnInfo.getControllerId(), etagReturnInfo, e.getMessage());
            }
        });
    }

    /**
     * 处理电子标签数据
     * @param etagReturnInfo 电子标签返回信息
     */
    private void etagDataHandler(EtagReturnInfo etagReturnInfo) {
        log.info("电子标签 {} 收到信息：{}", etagReturnInfo.getControllerId(), etagReturnInfo);
        Integer tagId = etagReturnInfo.getTagId(); // 标签号
        String controllerId = etagReturnInfo.getControllerId(); // 控制器ID
        AppEtagTagInfo appEtagTagInfo = etagRedis.getEtagTag(controllerId, tagId);
        if(appEtagTagInfo == null) {
            log.warn("电子标签信息：{}，未找到标签信息，无法处理事件", etagReturnInfo);
            return; // 找不到标签信息
        }
        Integer tagType = appEtagTagInfo.getTagType();
        if(Objects.equals(tagType, ETagTypeEnum.SCAN.getCode())) {
            handScanCode(appEtagTagInfo, etagReturnInfo);
            return;
        }
        if(ETagTypeEnum.buttonTagList().contains(ETagTypeEnum.getByCode(tagType))) {
            handleTagConfirm(appEtagTagInfo, etagReturnInfo);
            return;
        }
    }

    /**
     * 处理扫码标签
     * @param appEtagTagInfo 标签信息
     * @param etagReturnInfo 扫码标签返回信息
     */
    private void handScanCode(AppEtagTagInfo appEtagTagInfo, EtagReturnInfo etagReturnInfo) {
        if(etagReturnInfo.getSubCommand().equals(EtagSubCommandEnum.CONFIRM_COMMAND.getCode())) {
            // ---- 正确提交
            String user = etagRedis.getEtagAreaUser(appEtagTagInfo.getAreaId());
            /* 用户相关 */
            boolean isUserBind = bindOrUnbindUser(appEtagTagInfo.getAreaId(), etagReturnInfo.getData(), user);
            if(isUserBind) {
                return; // 如果是用户绑定相关的功能则单独处理，此处返回
            }
            /* 扫描条码相关 */
            // 检查是否有任务
            List<Integer> taskStatusList = List.of(EtagTaskStatusEnum.NOT_ACTIVATED.getCode());
            List<AppEtagTask> appEtagTaskList = etagTaskService.queryByTagAreaIdAndVehicleAndStatus(appEtagTagInfo.getAreaId(), etagReturnInfo.getData(), taskStatusList);
            if(appEtagTaskList == null) {
                log.info("电子标签区域： {} 扫码： {}，任务检索失败", appEtagTagInfo.getAreaId(), etagReturnInfo.getData());
                EtagLightParams lightParams = EtagLightParams.builder()
                        .tagName(appEtagTagInfo.getTagName())
                        .tagId(appEtagTagInfo.getTagId().byteValue())
                        .tagValue("")
                        .tagString("任务检索异常")
                        .ledBlinking(LedBlinkingEnum.BLINKING_0_25)
                        .ledColor(LedColorEnum.RED)
                        .build();
                lightAreaSummaryTag(appEtagTagInfo.getAreaId(), lightParams);
                return;
            }
            if(appEtagTaskList.isEmpty()) {
                log.info("电子标签区域： {} 扫码： {}，无电子标签任务", appEtagTagInfo.getAreaId(), etagReturnInfo.getData());
                EtagLightParams lightParams = EtagLightParams.builder()
                        .tagName(appEtagTagInfo.getTagName())
                        .tagId(appEtagTagInfo.getTagId().byteValue())
                        .tagValue("0")
                        .tagString("任务完成")
                        .ledBlinking(LedBlinkingEnum.LED_ON)
                        .ledColor(LedColorEnum.GREEN)
                        .build();
                lightAreaSummaryTag(appEtagTagInfo.getAreaId(), lightParams);
                return;
            }
            log.info("电子标签区域： {} 扫码： {}，电子标签任务数量：{}", appEtagTagInfo.getAreaId(), etagReturnInfo.getData(), appEtagTaskList.size());
            EtagLightParams lightParams = EtagLightParams.builder()
                    .tagName(appEtagTagInfo.getTagName())
                    .tagId(appEtagTagInfo.getTagId().byteValue())
                    .tagValue(String.valueOf(appEtagTaskList.size()))
                    .tagString("正在捡货:" + etagReturnInfo.getData())
                    .ledBlinking(LedBlinkingEnum.LED_ON)
                    .ledColor(LedColorEnum.ORANGE)
                    .build();
            lightAreaSummaryTag(appEtagTagInfo.getAreaId(), lightParams);
            etagRedis.setEtagAreaVehicle(appEtagTagInfo.getAreaId(), etagReturnInfo.getData()); // 将扫码条码存储
            return;
        }
        EtagSubCommandEnum subCommandEnum = EtagSubCommandEnum.getByCode(etagReturnInfo.getSubCommand());
        String desc = subCommandEnum == null ? String.valueOf(etagReturnInfo.getSubCommand()) : subCommandEnum.getDesc();
        log.info("电子标签扫码器 {}，返回非正常提交类型：{}", etagReturnInfo, desc);
    }

    /**
     * 区域用户绑定或解绑
     * @param areaId 区域ID
     * @param data 数据
     * @param user 用户
     * @return 是否处理成功
     */
    private boolean bindOrUnbindUser(String areaId, String data, String user) {
        // 判断区域用户绑定
        if(data.equals(etagConfig.getAreaUserUnbind())) {
            etagRedis.setEtagAreaUser(areaId, "");
            log.info("电子标签区域 {} 解绑用户", areaId);
            EtagLightParams lightParams = EtagLightParams.builder()
                    .tagValue(user)
                    .tagString("解绑用户")
                    .ledBlinking(LedBlinkingEnum.BLINKING_0_25)
                    .ledColor(LedColorEnum.RED)
                    .build();
            lightAreaSummaryTag(areaId, lightParams);
            AppThreadUtils.sleep(1500); // 点亮标签 1.5秒
            EtagLightParams offParams = EtagLightParams.builder()
                    .tagValue(user)
                    .tagString("解绑用户")
                    .ledBlinking(LedBlinkingEnum.LED_OFF)
                    .ledColor(LedColorEnum.RED)
                    .build();
            lightAreaSummaryTag(areaId, offParams);
            return true;
        }
        if(data.equals(etagConfig.getAreaUserPrefix())) {
            etagRedis.setEtagAreaUser(areaId, etagConfig.getAreaUserPrefix());
            log.info("电子标签区域 {} 准备绑定用户", areaId);
            EtagLightParams lightParams = EtagLightParams.builder()
                    .tagValue("888")
                    .tagString("请扫描用户码")
                    .ledBlinking(LedBlinkingEnum.BLINKING_0_25)
                    .ledColor(LedColorEnum.GREEN)
                    .build();
            lightAreaSummaryTag(areaId, lightParams);
            return true;
        }
        if(user != null && user.equals(etagConfig.getAreaUserPrefix())) {
            etagRedis.setEtagAreaUser(areaId, data);
            log.info("电子标签区域 {} 绑定用户：{}", areaId, data);
            EtagLightParams lightParams = EtagLightParams.builder()
                    .tagValue(user)
                    .tagString("绑定成功")
                    .ledBlinking(LedBlinkingEnum.LED_ON)
                    .ledColor(LedColorEnum.PINK)
                    .build();
            lightAreaSummaryTag(areaId, lightParams);
            AppThreadUtils.sleep(1500); // 点亮标签 1.5秒
            EtagLightParams offParams = EtagLightParams.builder()
                    .tagValue(user)
                    .tagString("绑定成功")
                    .ledBlinking(LedBlinkingEnum.LED_OFF)
                    .ledColor(LedColorEnum.PINK)
                    .build();
            lightAreaSummaryTag(areaId, offParams);
            return true;
        }
        return false;
    }


    /**
     * 点亮区域标签
     * @param areaId 区域
     * @param lightParams 点亮标签参数
     */
    private void lightAreaSummaryTag(String areaId, EtagLightParams lightParams) {
        AppEtagTagInfo querySummaryTag = new AppEtagTagInfo();
        querySummaryTag.setAreaId(areaId);
        querySummaryTag.setBusinessType(EtagBusinessTypeEnum.AREA.getCode());
        List<AppEtagTagInfo> tagInfos = etagInfoService.queryIgnoreNull(querySummaryTag);
        if(tagInfos == null || tagInfos.isEmpty()) {
            log.warn("电子标签区域 {} 无汇总标签", areaId);
            return;
        }
        for (AppEtagTagInfo tagInfo : tagInfos) {
            EtagLightParams tagLightParams = EtagLightParams.builder()
                    .tagName(tagInfo.getTagName())
                    .tagId(tagInfo.getTagId().byteValue())
                    .tagValue(lightParams.getTagValue())
                    .tagString(lightParams.getTagString())
                    .ledColor(lightParams.getLedColor())
                    .ledBlinking(lightParams.getLedBlinking())
                    .build();
            String lightTagResult = etagAtopOperation.lightTag(tagLightParams);
            log.info("点亮电子标签: {}，点亮参数：{}，点亮结果：{}", tagInfo, tagLightParams, lightTagResult);
        }
    }


    /**
     * 处理标签按下确认
     * @param appEtagTagInfo 标签信息
     * @param etagReturnInfo 标签按下确认返回信息
     */
    private void handleTagConfirm(AppEtagTagInfo appEtagTagInfo, EtagReturnInfo etagReturnInfo) {
        if(Objects.equals(appEtagTagInfo.getBusinessType(), EtagBusinessTypeEnum.AREA.getCode())) {
            // 区域总标签按下
            handleSummaryTagConfirm(appEtagTagInfo, etagReturnInfo);
            return;
        }
        if(Objects.equals(appEtagTagInfo.getBusinessType(), EtagBusinessTypeEnum.NORMAL.getCode())) {
            // 普通标签按下
            handleNormalTagConfirm(appEtagTagInfo, etagReturnInfo);
            return;
        }
        log.info("未知业务标签发来确认：{};{}", appEtagTagInfo, etagReturnInfo);
    }

    /**
     * 处理区域总标签按下
     * @param appEtagTagInfo 标签信息
     * @param etagReturnInfo 标签按下确认返回信息
     */
    private void handleSummaryTagConfirm(AppEtagTagInfo appEtagTagInfo, EtagReturnInfo etagReturnInfo) {
        if(etagReturnInfo.getSubCommand().equals(EtagSubCommandEnum.CONFIRM_COMMAND.getCode())) {
            // 按下确认键 ---- 区域标签按下时检查是否还有没捡选任务，若有则再次点亮标签
            String vehicleNo = etagRedis.getEtagAreaVehicle(appEtagTagInfo.getAreaId());
            if(AppStringUtils.isEmpty(vehicleNo)) {
                log.info("电子标签区域： {} 区域标签按下，载具编号未绑定", appEtagTagInfo.getAreaId());
                return;
            }
            // 检查是否有任务
            List<Integer> taskStatusList = List.of(EtagTaskStatusEnum.NOT_ACTIVATED.getCode(), EtagTaskStatusEnum.LIGHTING.getCode());
            List<AppEtagTask> appEtagTaskList = etagTaskService.queryByTagAreaIdAndVehicleAndStatus(appEtagTagInfo.getAreaId(), vehicleNo, taskStatusList);
            if(appEtagTaskList == null) {
                log.info("电子标签区域： {} 区域标签按下： {}，任务检索失败", appEtagTagInfo.getAreaId(), vehicleNo);
                EtagLightParams lightParams = EtagLightParams.builder()
                        .tagName(appEtagTagInfo.getTagName())
                        .tagId(appEtagTagInfo.getTagId().byteValue())
                        .tagValue("")
                        .tagString("任务检索异常")
                        .ledBlinking(LedBlinkingEnum.BLINKING_0_25)
                        .ledColor(LedColorEnum.RED)
                        .build();
                lightAreaSummaryTag(appEtagTagInfo.getAreaId(), lightParams);
                return;
            }
            if(appEtagTaskList.isEmpty()) {
                log.info("电子标签区域： {} 区域标签按下： {}，无电子标签任务", appEtagTagInfo.getAreaId(), vehicleNo);
                return;
            }
            log.info("电子标签区域： {} 区域标签按下： {}，电子标签任务数量：{}", appEtagTagInfo.getAreaId(), vehicleNo, appEtagTaskList.size());
            EtagLightParams lightParams = EtagLightParams.builder()
                    .tagName(appEtagTagInfo.getTagName())
                    .tagId(appEtagTagInfo.getTagId().byteValue())
                    .tagValue(String.valueOf(appEtagTaskList.size()))
                    .tagString("还需捡货:" + vehicleNo)
                    .ledBlinking(LedBlinkingEnum.LED_ON)
                    .ledColor(LedColorEnum.ORANGE)
                    .build();
            lightAreaSummaryTag(appEtagTagInfo.getAreaId(), lightParams);
            return;
        }
        EtagSubCommandEnum subCommandEnum = EtagSubCommandEnum.getByCode(etagReturnInfo.getSubCommand());
        String desc = subCommandEnum == null ? String.valueOf(etagReturnInfo.getSubCommand()) : subCommandEnum.getDesc();
        log.info("电子标签区域标签 {}，返回非正常提交类型：{}", etagReturnInfo, desc);
    }

    /**
     * 处理普通标签按下
     * @param appEtagTagInfo 标签信息
     * @param etagReturnInfo 标签按下确认返回信息
     */
    private void handleNormalTagConfirm(AppEtagTagInfo appEtagTagInfo, EtagReturnInfo etagReturnInfo) {
        log.info("电子标签普通标签 {}，返回确认信息：{}", appEtagTagInfo.getTagName(), etagReturnInfo.getData());
        if(etagReturnInfo.getSubCommand().equals(EtagSubCommandEnum.CONFIRM_COMMAND.getCode())) {
            // 按下确认键
            AppEtagTask etagTagTask = etagRedis.getEtagTagTask(appEtagTagInfo.getTagName());
            if(etagTagTask == null) {
                log.info("电子标签普通标签 {}，未检索到任务", appEtagTagInfo.getTagName());
                return;
            }
            etagRedis.removeEtagTagTask(appEtagTagInfo.getTagName()); // 解绑这个标签绑定的任务
            // 更新确认数量和确认人
            String user = etagRedis.getEtagAreaUser(appEtagTagInfo.getAreaId()); // 确认人
            int confirmNum = AppStringUtils.forceToInt(etagReturnInfo.getData());
            AppEtagTask updateEtagTagTask = new AppEtagTask();
            updateEtagTagTask.setTaskId(etagTagTask.getTaskId());
            updateEtagTagTask.setTaskStatus(EtagTaskStatusEnum.CONFIRM.getCode());
            updateEtagTagTask.setConfirmTime(LocalDateTime.now());
            updateEtagTagTask.setCompletedTime(LocalDateTime.now());
            updateEtagTagTask.setConfirmNum(BigDecimal.valueOf(confirmNum));
            updateEtagTagTask.setConfirmPerson(user);
            Integer result = etagTaskService.updateIgnoreNull(updateEtagTagTask).result();
            log.info("电子标签普通标签 {}，更新任务：{}，结果：{}", appEtagTagInfo.getTagName(), etagTagTask.getTaskId(), result);
            // 上报电子标签任务
            if(etagTagTask.getTaskSource().equals(ConstantData.SYSTEM_NAME)) {
                return; // 自己创建的不需要上报
            }
            Tuple2<String, String> reportResult = ReportStandard.etagTaskReport(etagTagTask, confirmNum, user);
            if(AppStringUtils.isEmpty(reportResult.item1)) {
                log.info("电子标签普通标签 {}，任务号：{}，上报任务失败：{}", appEtagTagInfo.getTagName(), etagTagTask.getTaskId(), reportResult.item1);
            } else {
                log.info("电子标签普通标签 {}，任务号：{}，上报任务结果：{}", appEtagTagInfo.getTagName(), etagTagTask.getTaskId(), reportResult.item2);
            }
            return;
        }
        EtagSubCommandEnum subCommandEnum = EtagSubCommandEnum.getByCode(etagReturnInfo.getSubCommand());
        String desc = subCommandEnum == null ? String.valueOf(etagReturnInfo.getSubCommand()) : subCommandEnum.getDesc();
        log.info("电子标签小标签 {}，返回非正常提交类型：{}", etagReturnInfo, desc);
    }

}
