package com.bonus.tcp.smartIdentify.controller;

import com.bonus.common.core.utils.BASE64DecodedMultipartFile;
import com.bonus.common.core.utils.DateTimeHelper;
import com.bonus.common.entity.tcp.DeviceUseVo;
import com.bonus.common.redis.service.RedisService;
import com.bonus.tcp.smartIdentify.service.SmartIdentifyService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @className:SmartIdentifyController
 * @author:cwchen
 * @date:2024-08-27-14:26
 * @version:1.0
 * @description:球机智能识别
 */
@Slf4j
@RestController
@RequestMapping("/ball")
public class SmartIdentifyController {

    @Autowired
    private RedisService redisService;

    @Resource(name = "SmartIdentifyService")
    private SmartIdentifyService service;

    public static final ReentrantLock BED_LOCK = new ReentrantLock();

    /**
     * 事件id集合
     * E_IVS_HelmetNotWear ：未带安全帽
     * E_IVS_Smoking ：抽烟报警
     * E_IVS_NotWear3ColorVest ：未穿三色马甲报警
     */
    public static List<String> eventIds = new ArrayList<>();

    {
        eventIds.add("E_IVS_HelmetNotWear");
        eventIds.add("E_IVS_Smoking");
        eventIds.add("E_IVS_NotWear3ColorVest");
    }

    /**
     * 清新互联平台事件推送接口
     *
     * @param xml
     * @return
     */
    @PostMapping("xmlAnalysis")
    public String xmlAnalysis(@RequestBody String xml) {
        try {
            // 设置对象锁
            boolean flag = BED_LOCK.tryLock(10L * 1000L, TimeUnit.MILLISECONDS);
            if (flag) {
                boolean existence = false;
                //解析xml字符串为Document
                Document doc = null;
                //事件ID
                String evenID = null;
                //身份证号
                String idCard = null;
                //事件时间
                String eventTime = DateTimeHelper.getNowTime();
                //解析xml内容
                doc = DocumentHelper.parseText(xml);
                //获取根节点
                Element root = doc.getRootElement();
                //获取根节点下的所有M子节点
                Iterator it = root.elementIterator("E");
                //获取单个事件
                if (it != null) {
                    Element element = (Element) it.next();
                    String id = element.attributeValue("ID");
                    evenID = id;
                    //获取事件发生时间
                    if (StringUtils.isNotBlank(element.attributeValue("Time"))) {
                        eventTime = DateTimeHelper.stampToDate(element.attributeValue("Time"));
                    }
                    Iterator desc2Interator = element.elementIterator("Desc2");
                    if (desc2Interator != null) {
                        Element idCardEle = (Element) desc2Interator.next();
                        idCard = idCardEle.attributeValue("IDCard");
                    }
                    Iterator srcInterator = element.elementIterator("Src");
                    String ballName = null;
                    if (srcInterator != null) {
                        Element headEle = (Element) srcInterator.next();
                        String puid = headEle.attributeValue("ID");
                        // 十分钟内存在该事件，直接返回
                        Object cacheObject = redisService.getCacheObject(evenID + "_" + puid);
                        if (Objects.nonNull(cacheObject)) {
                            log.info("十分钟内存在该事件");
                            return "error";
                        }
                        Iterator resInterator = headEle.elementIterator("Res");
                        if (resInterator != null) {
                            Element nameEle = (Element) resInterator.next();
                            ballName = nameEle.attributeValue("Name");
                        }
                        boolean sf = eventIds.contains(evenID);
                        List<DeviceUseVo> devices = null;
                        if (sf) {
                            devices = service.getDevices(puid);
                            existence = CollectionUtils.isNotEmpty(devices) ? true : false;
                        }
                        //存在该设备
                        if (existence) {
                            switchEvent(evenID, element, eventTime, puid, ballName, idCard, devices);
                            // 事件推送成功后，设置缓存
                            String key = evenID + "_" + puid;
                            log.info("redis-key:{}", key);
                            redisService.setCacheObject(key, puid, 1L, TimeUnit.MINUTES);
                        } else {
                            return "error";
                        }
                    } else {
                        return "error";
                    }
                } else {
                    return "error";
                }
            } else {
                log.info("系统繁忙，请稍后重试");
                return "error";
            }
        } catch (InterruptedException e) {
            log.error("对象锁", e);
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        } finally {
            // 确保锁被释放
            BED_LOCK.unlock();
        }
        return "ok";
    }

    private void switchEvent(String eventId, Element element, String eventTime, String puid, String ballName, String idCard, List<DeviceUseVo> devices) {
        List<MultipartFile> files = null;
        DeviceUseVo deviceUseVo = devices.get(0);
        deviceUseVo.setWarnTime(eventTime);
        deviceUseVo.setIdCard(idCard);
        switch (eventId) {
            case "E_IVS_HelmetNotWear":
                log.info(puid + ":违章事件：未戴安全帽");
                deviceUseVo.setWarnContent("未戴安全帽");
                files = deviceVolEvenHandler(element);
                service.addEventData(deviceUseVo, files);
                break;
            case "E_IVS_Smoking":
                log.info(puid + ":违章事件：吸烟行为");
                deviceUseVo.setWarnContent("吸烟行为");
                files = deviceVolEvenHandler(element);
                service.addEventData(deviceUseVo, files);
                break;
            case "E_IVS_NotWear3ColorVest":
                log.info(puid + ":违章事件：未穿马甲");
                deviceUseVo.setWarnContent("未穿马甲");
                files = deviceVolEvenHandler(element);
                service.addEventData(deviceUseVo, files);
                break;
            default:
                break;
        }
    }

    private List<MultipartFile> deviceVolEvenHandler(Element element) {
        List<MultipartFile> multipartFiles = new ArrayList<>();
        Iterator silcesInterator = element.elementIterator("Slices");
        if (silcesInterator.hasNext()) {
            Element silcesEle = (Element) silcesInterator.next();
            if (silcesEle != null) {
                Iterator silcInterator = silcesEle.elementIterator("Slice");
                if (silcInterator.hasNext()) {
                    Element snapshotEle = (Element) silcInterator.next();
                    if (snapshotEle != null) {
                        Iterator snapshotInterator = snapshotEle.elementIterator("Snapshot");
                        if (snapshotInterator.hasNext()) {
                            Element TestEle = (Element) snapshotInterator.next();
                            String photoBase64 = TestEle.getText();
                            log.info("base64地址：{}", photoBase64);
                            MultipartFile multipartFile = BASE64DecodedMultipartFile.base64ToMultipart2(photoBase64);
                            if (multipartFile != null) {
                                multipartFiles.add(multipartFile);
                            }
                        }
                    }
                }
            }
        }
        return multipartFiles;
    }
}
