package com.yeejoin.amos.boot.module.statistcs.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yeejoin.amos.boot.biz.common.dto.CommonVideoDto;
import com.yeejoin.amos.boot.biz.common.entity.BaseEntity;
import com.yeejoin.amos.boot.module.common.api.dto.DPFilterParamDto;
import com.yeejoin.amos.boot.module.common.api.entity.BaseEnterpriseVideo;
import com.yeejoin.amos.boot.module.common.api.entity.BaseEnterpriseVideoNode;
import com.yeejoin.amos.boot.module.common.api.enums.VideoIntegrationPlatformEnum;
import com.yeejoin.amos.boot.module.common.api.utils.DateUtils;
import com.yeejoin.amos.boot.module.common.biz.service.impl.BaseEnterpriseVideoNodeServiceImpl;
import com.yeejoin.amos.boot.module.common.biz.service.impl.BaseEnterpriseVideoServiceImpl;
import com.yeejoin.amos.boot.module.statistcs.biz.utils.JsonUtils;
import com.yeejoin.amos.boot.module.statistics.api.dto.UnitVideoDto;
import com.yeejoin.amos.boot.module.statistics.api.vo.TreeNodeVo;
import com.yeejoin.amos.boot.module.ymt.api.dto.TzBaseEnterpriseInfoDto;
import com.yeejoin.amos.boot.module.ymt.api.entity.TzBaseEnterpriseInfo;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.TzBaseEnterpriseInfoMapper;
import com.yeejoin.amos.feign.systemctl.model.RegionModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Administrator
 */
@Service
@Slf4j
public class VideoServiceImpl {

    private static String NODE_TYPE_REGION = "region";

    private static String NODE_TYPE_UNIT = "unit";

    private static String NODE_TYPE_VIDEO = "video";

    @Value("classpath:/json/region.json")
    private Resource regionJson;

    private TzBaseEnterpriseInfoMapper tzBaseEnterpriseInfoMapper;
    @Autowired
    private BaseEnterpriseVideoNodeServiceImpl baseEnterpriseVideoNodeService;
    private StCommonServiceImpl stCommonService;

    private BaseEnterpriseVideoServiceImpl enterpriseVideoService;


    public VideoServiceImpl(BaseEnterpriseVideoServiceImpl enterpriseVideoService, TzBaseEnterpriseInfoMapper tzBaseEnterpriseInfoMapper, StCommonServiceImpl stCommonService) {
        this.enterpriseVideoService = enterpriseVideoService;
        this.tzBaseEnterpriseInfoMapper = tzBaseEnterpriseInfoMapper;
        this.stCommonService = stCommonService;
    }

    /**
     * 按照区域信息，进行显示区域（可能多层级）、单位（可能在多个区域下）、摄像头（在单位节点下）树
     *
     * @param dpFilterParamDto 区域信息
     * @return List<TreeNodeVo>
     */
    public List<TreeNodeVo> getVideoTree(DPFilterParamDto dpFilterParamDto) {
        // 摄像头设备参数配置
        List<BaseEnterpriseVideo> videoEquipList = getVideos(dpFilterParamDto.getCityCode());

        List<BaseEnterpriseVideoNode> videoNodesList = getVideoNodes(dpFilterParamDto.getCityCode());
        // 摄像头对应的单位列表
        List<TzBaseEnterpriseInfo> baseEnterpriseInfos = this.getUnitListForTree(videoNodesList.stream().map(BaseEnterpriseVideoNode::getUseUnitCode).collect(Collectors.toSet()));
        // 摄像头对应的行政区域列表
        List<RegionModel> regionModels = this.getRegionListOfVideo(videoNodesList);
        // 摄像头通道
        List<CommonVideoDto> channelNoList = this.getVideoChannel(videoEquipList,videoNodesList);
        // 树组装
        return castList2Tree(baseEnterpriseInfos, regionModels, channelNoList, videoNodesList);
    }

    private List<BaseEnterpriseVideoNode> getVideoNodes(String regionCode) {
        LambdaQueryWrapper<BaseEnterpriseVideoNode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BaseEnterpriseVideoNode::getEquListCode, EquipmentClassifityEnum.KYSD.getCode());
        queryWrapper.like(BaseEnterpriseVideoNode::getRegionCode, regionCode);
        queryWrapper.eq(BaseEnterpriseVideoNode::getIsDelete, true);
        return baseEnterpriseVideoNodeService.list(queryWrapper);
    }

    private List<TreeNodeVo> castList2Tree(List<TzBaseEnterpriseInfo> baseEnterpriseInfos, List<RegionModel> regionModels, List<CommonVideoDto> channelNoList, List<BaseEnterpriseVideoNode> videoNodesList) {
        // 数据处理，把行政区域、单位、摄像头 数据格式化为有parent的标准树结构列表
        List<TreeNodeVo> regionNodes = regionModels.stream().map(r -> {
            TreeNodeVo treeNodeVo = new TreeNodeVo();
            treeNodeVo.setNodeType(NODE_TYPE_REGION);
            treeNodeVo.setId(r.getSequenceNbr().toString());
            treeNodeVo.setName(r.getRegionName());
            treeNodeVo.setCode(r.getRegionCode() + "");
            treeNodeVo.setParentId(String.valueOf(r.getParentId()));
            return treeNodeVo;
        }).collect(Collectors.toList());
        // 区域拼接为树结构
        List<TreeNodeVo> treeNodeVos = regionNodes.stream().filter(r -> StringUtils.isEmpty(r.getParentId()) || "0".equals(r.getParentId())).map(r -> {
            TreeNodeVo treeNodeVo = new TreeNodeVo();
            BeanUtil.copyProperties(r, treeNodeVo);
            treeNodeVo.setChildren(this.getRegionTypeNode(treeNodeVo, regionNodes));
            return treeNodeVo;
        }).collect(Collectors.toList());
        // 给区域的最下级增加直接下级->单位，id不是其他的parent_id则为树的叶子节点
        treeNodeVos.forEach(t -> {
            this.setChildrenUnitTypeNode(regionNodes, t, baseEnterpriseInfos, videoNodesList, channelNoList);
        });
        return treeNodeVos;
    }

    private void setChildrenUnitTypeNode(List<TreeNodeVo> regionNodes, TreeNodeVo parentNode, List<TzBaseEnterpriseInfo> baseEnterpriseInfos, List<BaseEnterpriseVideoNode> videoNodesList, List<CommonVideoDto> channelNoList) {
        if (regionNodes.stream().noneMatch(e -> parentNode.getId().equals(e.getParentId()))) {
            parentNode.setChildren(this.buildUnitTypeNode(baseEnterpriseInfos, videoNodesList, channelNoList, parentNode));
        } else {
            parentNode.getChildren().forEach(p -> {
                setChildrenUnitTypeNode(regionNodes, p, baseEnterpriseInfos, videoNodesList, channelNoList);
            });
        }
    }

    private List<TreeNodeVo> getRegionTypeNode(TreeNodeVo parentNode, List<TreeNodeVo> regionNodes) {
        return regionNodes.stream().filter(r -> StringUtils.isNotEmpty(r.getParentId()) && r.getParentId().equals(parentNode.getId())).map(r -> {
            TreeNodeVo treeNodeVo = new TreeNodeVo();
            BeanUtil.copyProperties(r, treeNodeVo);
            treeNodeVo.setChildren(this.getRegionTypeNode(treeNodeVo, regionNodes));
            return treeNodeVo;
        }).collect(Collectors.toList());
    }


    private List<TreeNodeVo> buildUnitTypeNode(List<TzBaseEnterpriseInfo> baseEnterpriseInfos, List<BaseEnterpriseVideoNode> videoNodesList, List<CommonVideoDto> channelNoList, TreeNodeVo parentNode) {
        Set<String> useUnitCodes = videoNodesList.stream().filter(v -> v.getRegionCode().contains(parentNode.getCode())).map(BaseEnterpriseVideoNode::getUseUnitCode).collect(Collectors.toSet());
        return baseEnterpriseInfos.stream().filter(v -> useUnitCodes.contains(v.getUseUnitCode())).map(u -> {
            TreeNodeVo treeNodeVo = new TreeNodeVo();
            treeNodeVo.setNodeType(NODE_TYPE_UNIT);
            // 防止id不唯一，拼接为{父id}_{本级id},目前左侧树与右侧列表没交互不定位，如需定位需要按照code进行定位
            treeNodeVo.setId(parentNode.getId() + "_" + u.getSequenceNbr());
            treeNodeVo.setName(u.getUseUnit());
            treeNodeVo.setCode(u.getUseUnitCode());
            treeNodeVo.setParentId(parentNode.getId());
            treeNodeVo.setChildren(this.buildVideoTypeNode(treeNodeVo, channelNoList));
            return treeNodeVo;
        }).collect(Collectors.toList());
    }

    private List<TreeNodeVo> buildVideoTypeNode(TreeNodeVo parentNode, List<CommonVideoDto> channelNoList) {
        // TODO 需按索道设备分组，萤石云和海康平台分别处理
        return channelNoList.stream().filter(v -> v.getParent().contains(parentNode.getCode())).map(u -> {
            TreeNodeVo treeNodeVo = new TreeNodeVo();
            treeNodeVo.setNodeType(NODE_TYPE_VIDEO);
            // 这个key需要全局唯一，用来页面左侧点击摄像头类型的节点时与右侧的摄像头列表进行定位
            // @see /video/list->CommonVideoDto.key
            treeNodeVo.setId(u.getKey());
            treeNodeVo.setName(u.getLabel());
            treeNodeVo.setParentId(parentNode.getId());
            return treeNodeVo;
        }).collect(Collectors.toList());
    }

    private List<CommonVideoDto> getVideoChannel(List<BaseEnterpriseVideo> videoEquipList,List<BaseEnterpriseVideoNode> videoNodesList) {
        List<CommonVideoDto> commonVideoDtos = new ArrayList<>();
        // 根据对接平台不同，摄像头通道信息不同，需要解析成CommonVideoDto
        List<BaseEnterpriseVideo> ysVideoList = videoEquipList.stream().filter(v -> VideoIntegrationPlatformEnum.YS.getCode().equals(v.getPlatform())).collect(Collectors.toList());
        if (!ValidationUtil.isEmpty(ysVideoList)) {
            ysVideoList.forEach(v -> {
                String channelNos = v.getChannelNo();
                List<CommonVideoDto> channelNoList = JSONObject.parseArray(channelNos, CommonVideoDto.class);
                commonVideoDtos.addAll(channelNoList.stream().peek(e -> e.setParent(v.getUseUnitCode())).collect(Collectors.toList()));
            });
        }
        List<CommonVideoDto> iSecureCenterCameras = enterpriseVideoService.getISecureCenterCameras(videoNodesList);
        if (!ValidationUtil.isEmpty(iSecureCenterCameras)) {
            commonVideoDtos.addAll(iSecureCenterCameras);
        }
        return commonVideoDtos;
    }

    private List<RegionModel> getRegionListOfVideo(List<BaseEnterpriseVideoNode> videoNodesList) {
        return stCommonService.getRegionModels().parallelStream().filter(r -> videoNodesList.stream().anyMatch(v -> v.getRegionCode().contains(r.getRegionCode().toString()))).collect(Collectors.toList());
    }

    private List<TzBaseEnterpriseInfo> getUnitListForTree(Set<String> useUnitCodes) {
        LambdaQueryWrapper<TzBaseEnterpriseInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(TzBaseEnterpriseInfo::getUseUnitCode, useUnitCodes);
        queryWrapper.select(TzBaseEnterpriseInfo::getUseUnitCode, TzBaseEnterpriseInfo::getUseUnit, TzBaseEnterpriseInfo::getAddress, BaseEntity::getSequenceNbr,TzBaseEnterpriseInfo::getOrgCode);
        return tzBaseEnterpriseInfoMapper.selectList(queryWrapper);
    }

    private List<BaseEnterpriseVideo> getVideos(String regionCode) {
        LambdaQueryWrapper<BaseEnterpriseVideo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BaseEnterpriseVideo::getEquListCode, EquipmentClassifityEnum.KYSD.getCode());
        queryWrapper.like(BaseEnterpriseVideo::getRegionCode, regionCode);
        queryWrapper.eq(BaseEnterpriseVideo::getIsEnabled, true);
        return enterpriseVideoService.list(queryWrapper);
    }

    public List<UnitVideoDto> getUnitList(String regionCode) {
        // 摄像头设备
        List<BaseEnterpriseVideo> videoEquipList = getVideos(regionCode);
        List<BaseEnterpriseVideoNode> entersList = baseEnterpriseVideoNodeService.list(new LambdaQueryWrapper<BaseEnterpriseVideoNode>().like(BaseEnterpriseVideoNode::getRegionCode, regionCode).groupBy(BaseEnterpriseVideoNode::getUseUnitCode));
        // 摄像头对应的单位列表
        List<TzBaseEnterpriseInfo> baseEnterpriseInfos = this.getUnitListForTree(entersList.stream().map(BaseEnterpriseVideoNode::getUseUnitCode).collect(Collectors.toSet()));
        return baseEnterpriseInfos.parallelStream().map(e -> {
            UnitVideoDto unitVideoDto = new UnitVideoDto();
            unitVideoDto.setId(e.getSequenceNbr() + "");
            unitVideoDto.setName(e.getUseUnit());
            unitVideoDto.setCode(e.getUseUnitCode());
            // 摄像头节点
            List<BaseEnterpriseVideoNode> videoNodesList = baseEnterpriseVideoNodeService.list(new LambdaQueryWrapper<BaseEnterpriseVideoNode>().eq(BaseEnterpriseVideoNode::getUseUnitCode, e.getUseUnitCode()));
            // 摄像头通道
            List<CommonVideoDto> channelNoList = this.getVideoChannel(videoEquipList,videoNodesList);
            unitVideoDto.setCountNum(channelNoList.stream().filter(c -> c.getParent().equals(e.getUseUnitCode())).count());
            return unitVideoDto;
        }).collect(Collectors.toList());
    }

    public List<CommonVideoDto> getVideoList(String useUnitCode, String regionCode) {
        return enterpriseVideoService.getUnitVideoUrl(useUnitCode, regionCode);
    }

    public boolean saveOrUpdateVideos(String sequenceNbr) {
        boolean result = true;
        try {
            result = saveOrUpdateVideo(sequenceNbr);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return result;
    }
    public boolean saveOrUpdateVideo(String sequenceNbr) throws Exception {
        BaseEnterpriseVideo baseEnterpriseVideo = enterpriseVideoService.getBaseMapper().selectById(sequenceNbr);
        String appKey = baseEnterpriseVideo.getAppKey();
        String appSecret = baseEnterpriseVideo.getAppSecret();
        String deviceSerial = baseEnterpriseVideo.getDeviceSerial();
        String url = "https://113.140.67.204:55443/artemis/api/resource/v1/regions/subRegions";
        String videoUrl = "https://113.140.67.204:55443/artemis/api/resource/v1/regions/regionIndexCode/cameras";
        //根据跟节点673f784dc4ae4cf681957386accd445c获取区域列表子节点 开始
        String regionsStr = enterpriseVideoService.getsubRegions(appKey, appSecret, url, deviceSerial);
        if (ValidationUtil.isEmpty(regionsStr)) {
            log.error("获取iSecureCenter视频对接平台区域列表失败,deviceSerial:{}", deviceSerial);
            return false;
        }
        JSONObject regionsResult = JSONObject.parseObject(regionsStr);
        if (regionsResult.get("data") == null) {
            log.error("获取iSecureCenter视频对接平台区域列表失败,data:{}", regionsStr);
            return false;
        }
        JSONArray regionsDataList = regionsResult.getJSONArray("data");
        if (ValidationUtil.isEmpty(regionsDataList)) {
            log.error("获取iSecureCenter视频对接平台区域列表失败,regionsDataList:{}", regionsDataList);
            return false;
        } else {
            Map<String, String> regionMaps=JsonUtils.getResourceJson(regionJson);
            regionsDataList.forEach(regionsData -> {
                JSONObject regionDataJson = (JSONObject) regionsData;
                String regionName = regionDataJson.getString("name");
                String regionIndexCode = regionDataJson.getString("indexCode");

                //根据区域regionIndexCode获取企业列表 开始
                String unitsStr = enterpriseVideoService.getsubRegions(appKey, appSecret, url, regionIndexCode);
                if (ValidationUtil.isEmpty(unitsStr)) {
                    log.error("获取iSecureCenter视频对接平台区域列表失败,deviceSerial:{}", regionIndexCode);
                }
                JSONObject unitsResult = JSONObject.parseObject(unitsStr);
                if (unitsResult.get("data") == null) {
                    log.error("获取iSecureCenter视频对接平台区域列表失败,data:{}", unitsStr);
                }
                JSONArray unitsDataList = unitsResult.getJSONArray("data");
                if (ValidationUtil.isEmpty(unitsDataList)) {
                    log.error("获取iSecureCenter视频对接平台区域列表失败,regionsDataList:{}", unitsDataList);
                } else {
                    unitsDataList.forEach(unitsData -> {
                        JSONObject unitDataJson = (JSONObject) unitsData;
                        String unitNameAndCode = unitDataJson.getString("name");
                        String unitName = unitNameAndCode==null?"":unitNameAndCode.split("#")[0];
                        String unitCode = unitNameAndCode==null?"":(unitNameAndCode.contains("#")?unitNameAndCode.split("#")[1]:"");
                        final String unitOrgCode;
                        if (null!=unitCode || !ValidationUtil.isEmpty(unitCode)) {
                            Set<String> setStr = new HashSet<String>();
                            setStr.add(unitCode);
                            List<TzBaseEnterpriseInfo> tzBaseEnterpriseInfos = getUnitListForTree(setStr);
                            unitOrgCode = tzBaseEnterpriseInfos.size() > 0? tzBaseEnterpriseInfos.get(0).getOrgCode() : null;
                        }else {
                            // 不满足条件时，赋值为空字符串（与原逻辑一致）
                            unitOrgCode = null;
                        }
                        String unitIndexCode = unitDataJson.getString("indexCode");
                        //根据单位unitIndexCode获取设备列表 开始
                        String devsStr = enterpriseVideoService.getsubRegions(appKey, appSecret, url, unitIndexCode);
                        if (ValidationUtil.isEmpty(devsStr)) {
                            log.error("获取iSecureCenter视频对接平台设备列表失败,deviceSerial:{}", unitIndexCode);
                        }
                        JSONObject devsResult = JSONObject.parseObject(devsStr);
                        if (devsResult.get("data") == null) {
                            log.error("获取iSecureCenter视频对接平台设备列表失败,data:{}", devsStr);
                        }
                        JSONArray devsDataList = devsResult.getJSONArray("data");
                        if (ValidationUtil.isEmpty(devsDataList)) {
                            log.error("获取iSecureCenter视频对接平台设备列表失败,regionsDataList:{}", devsDataList);
                        } else {
                            devsDataList.forEach(devsData -> {
                                JSONObject devDataJson = (JSONObject) devsData;
                                String devName = devDataJson.getString("name");
                                String devIndexCode = devDataJson.getString("indexCode");
                                String camerasStr = enterpriseVideoService.getCameras(appKey, appSecret, videoUrl, devIndexCode);
                                if (ValidationUtil.isEmpty(camerasStr)) {
                                    log.error("获取iSecureCenter视频对接平台区域列表失败,deviceSerial:{}", deviceSerial);
                                }
                                JSONObject camerasResult = JSONObject.parseObject(camerasStr);
                                if (camerasResult.get("data") == null) {
                                    log.error("获取iSecureCenter视频对接平台区域列表失败,data:{}", camerasStr);
                                }
                                JSONObject camerasDataList = (JSONObject) camerasResult.get("data");
                                JSONArray cameraDataList = camerasDataList.getJSONArray("list");
                                if (ValidationUtil.isEmpty(camerasDataList)) {
                                    log.error("获取iSecureCenter视频对接平台区域列表失败,regionsDataList:{}", camerasDataList);
                                } else {
                                    cameraDataList.forEach(cameraData -> {
                                        JSONObject cameraDataJson = (JSONObject) cameraData;
                                        String cameraName = cameraDataJson.getString("cameraName");
                                        String useInstallCode = cameraDataJson.getString("installLocation");
                                        String reIndexCode = cameraDataJson.getString("regionIndexCode");
                                        String cameraIndexCode = cameraDataJson.getString("cameraIndexCode");
                                        String updateTime = cameraDataJson.getString("updateTime");
                                        String createTime = cameraDataJson.getString("createTime");
                                        String regionCode = regionMaps.get(regionName);
                                        BaseEnterpriseVideoNode enterpriseVideoNode = new BaseEnterpriseVideoNode();
                                        enterpriseVideoNode.setUseUnitName(unitName);
                                        enterpriseVideoNode.setUseUnitCode(unitCode);
                                        enterpriseVideoNode.setRegionName(regionName);
                                        enterpriseVideoNode.setRegionCode(regionCode);
                                        enterpriseVideoNode.setOrgCode(unitOrgCode);
                                        enterpriseVideoNode.setVideoName(cameraName);
                                        enterpriseVideoNode.setDevUseCode(useInstallCode);
                                        enterpriseVideoNode.setIsDelete(true);
                                        enterpriseVideoNode.setCameraIndexCode(cameraIndexCode);
                                        enterpriseVideoNode.setVideoSeq(Long.parseLong(sequenceNbr));
                                        enterpriseVideoNode.setEquListCode(EquipmentClassifityEnum.KYSD.getCode());
                                        try {
                                          //  enterpriseVideoNode.setRecDate(DateUtils.dateParseWithPattern(createTime));
                                            enterpriseVideoNode.setUpdatesTime(DateUtils.dateParseWithZonedDateTime(updateTime));
                                        } catch (ParseException e) {
                                            throw new RuntimeException(e);
                                        }
                                        baseEnterpriseVideoNodeService.saveOrUpdates(enterpriseVideoNode,cameraIndexCode);
                                    });
                                }
                            });
                        }
                    });
                }
            });
        }

        return true;
    }
}
