/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.device.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springblade.common.constant.CommonConstant;
import org.springblade.community.entity.Agency;
import org.springblade.community.entity.Building;
import org.springblade.community.entity.Floor;
import org.springblade.community.entity.Residential;
import org.springblade.community.feign.IAgencyClient;
import org.springblade.community.feign.IBuildingClient;
import org.springblade.community.feign.IFloorClient;
import org.springblade.community.feign.IResidentialClient;
import org.springblade.community.vo.AgencyVO;
import org.springblade.community.vo.BuildingVO;
import org.springblade.community.vo.FloorVO;
import org.springblade.community.vo.ResidentialVO;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.device.entity.GbDeviceChannel;
import org.springblade.device.vo.GbDeviceChannelTreeVO;
import org.springblade.device.vo.GbDeviceChannelVO;
import org.springblade.device.mapper.GbDeviceChannelMapper;
import org.springblade.device.service.IGbDeviceChannelService;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.third.videodevice.gb28181.feign.IThirdGbDeviceClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.util.Assert;

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

/**
 *  服务实现类
 *
 * @author BladeX
 * @since 2021-12-06
 */
@Service
public class GbDeviceChannelServiceImpl extends BaseServiceImpl<GbDeviceChannelMapper, GbDeviceChannel> implements IGbDeviceChannelService {

	@Autowired
	private IThirdGbDeviceClient thirdGbDeviceClient;
	@Autowired
	private IAgencyClient agencyClient;
	@Autowired
	private IResidentialClient residentialClient;
	@Autowired
	private IBuildingClient buildingClient;
	@Autowired
	private IFloorClient floorClient;

	@Override
	public IPage<GbDeviceChannelVO> selectGbDeviceChannelPage(IPage<GbDeviceChannelVO> page, GbDeviceChannelVO gbDeviceChannel) {
		return page.setRecords(baseMapper.selectGbDeviceChannelPage(page, gbDeviceChannel));
	}

	@Override
	public R submitBatch(List<GbDeviceChannel> gbDeviceChannelList) {
		for(GbDeviceChannel channel : gbDeviceChannelList){
			GbDeviceChannel dbChannel = this.getByChannelId(channel.getDeviceId(), channel.getChannelId());
			if(dbChannel == null){
				return R.status(this.save(channel));
			}else{
				channel.setId(dbChannel.getId());
				channel.setUpdateTime(new Date());
				return R.status(this.updateById(channel));
			}
		}
		return R.status(true);
	}

	@Override
	public GbDeviceChannel getByChannelId(String deviceId, String channelId) {
		LambdaQueryWrapper<GbDeviceChannel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(GbDeviceChannel::getDeviceId, deviceId);
		lambdaQueryWrapper.eq(GbDeviceChannel::getChannelId, channelId);
		return baseMapper.selectOne(lambdaQueryWrapper);
	}

	@Override
	public R<JSONObject> play(String deviceId, String channelId) {
		R<JSONObject> playResult = thirdGbDeviceClient.play(deviceId, channelId);
		if(playResult.isSuccess()){
			JSONObject data = playResult.getData();
			GbDeviceChannel channel = this.getByChannelId(deviceId, channelId);
			channel.setStreamId(data.getString("streamId"));
			baseMapper.updateById(channel);
		}
		return playResult;
	}

	@Override
	public R<String> stop(String deviceId, String channelId) {
		R<String> stopResult = thirdGbDeviceClient.stop(deviceId, channelId);
		if(stopResult.isSuccess()){
			GbDeviceChannel channel = this.getByChannelId(deviceId, channelId);
			channel.setStreamId(null);
			baseMapper.updateById(channel);
		}
		return stopResult;
	}

	@Override
	public List<GbDeviceChannel> selectByDeviceIds(List<String> deviceIdList) {
		LambdaQueryWrapper<GbDeviceChannel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.in(GbDeviceChannel::getDeviceId, deviceIdList);
		return this.list(lambdaQueryWrapper);

	}

	@Override
	public List<GbDeviceChannelTreeVO> lazyTree(String parentColumn, Long parentId) {
		String tenantId = AuthUtil.getTenantId();
		List<GbDeviceChannelTreeVO> treeVOList = new ArrayList<>();
		if(parentColumn.equals("0")){
			if(tenantId.equals("000000")){
				List<AgencyVO> agencyList = agencyClient.list(new Agency());
				for(AgencyVO agencyVO : agencyList){
					GbDeviceChannelTreeVO vo = new GbDeviceChannelTreeVO();
					List<GbDeviceChannel> listByAgency = listByAgencyId(agencyVO.getId());
					if(listByAgency.size() > 0){
						vo.setHasChildren(true);
						vo.setId(agencyVO.getId());
						vo.setLabel(agencyVO.getName());
						vo.setParentId(0L);
						vo.setParentLabelName("");
						treeVOList.add(vo);
					}
				}
			}else{
				Map<String, Object> residentialMap = new HashMap<>();
				residentialMap.put("tenantId", tenantId);
				List<ResidentialVO> residentialVOList = residentialClient.list(residentialMap);
				for(ResidentialVO residentialVO : residentialVOList){
					GbDeviceChannelTreeVO vo = new GbDeviceChannelTreeVO();
					List<GbDeviceChannel> listByResidential = listByResidentialId(parentId, residentialVO.getId());
					if(listByResidential.size() > 0){
						vo.setHasChildren(true);
						vo.setId(residentialVO.getId());
						vo.setLabel(residentialVO.getName());
						vo.setParentId(parentId);
						treeVOList.add(vo);
					}
				}
			}
		}else if(parentColumn.equals("agency")){
			Map<String, Object> residentialMap = new HashMap<>();
			residentialMap.put("agencyId", parentId);
			List<ResidentialVO> residentialVOList = residentialClient.list(residentialMap);
			for(ResidentialVO residentialVO : residentialVOList){
				GbDeviceChannelTreeVO vo = new GbDeviceChannelTreeVO();
				List<GbDeviceChannel> listByResidential = listByResidentialId(parentId, residentialVO.getId());
				if(listByResidential.size() > 0){
					vo.setHasChildren(true);
					vo.setId(residentialVO.getId());
					vo.setLabel(residentialVO.getName());
					vo.setParentId(parentId);
					treeVOList.add(vo);
				}
			}
		}else if(parentColumn.equals("residential")){
			List<GbDeviceChannel> listByResidential = listByResidentialId(null, parentId);
			for(GbDeviceChannel channel : listByResidential){
				GbDeviceChannelTreeVO vo = new GbDeviceChannelTreeVO();
				if(channel.getBuildingId() == null){
					vo.setHasChildren(false);
					vo.setId(channel.getId());
					vo.setLabel(channel.getName());
					vo.setParentId(parentId);
					vo.setDeviceId(channel.getDeviceId());
					vo.setChannelId(channel.getChannelId());
				}else{
					vo.setHasChildren(true);
					Building building = buildingClient.getById(channel.getBuildingId());
					vo.setId(building.getId());
					vo.setLabel(building.getName());
					vo.setParentId(parentId);
				}
				treeVOList.add(vo);
			}
		}else if(parentColumn.equals("building")){
			List<GbDeviceChannel> listByBuilding = listByBuildingId(null, null, parentId);
			for(GbDeviceChannel channel : listByBuilding){
				GbDeviceChannelTreeVO vo = new GbDeviceChannelTreeVO();
				if(channel.getFloorId() == null){
					vo.setHasChildren(false);
					vo.setId(channel.getId());
					vo.setLabel(channel.getName());
					vo.setParentId(parentId);
					vo.setDeviceId(channel.getDeviceId());
					vo.setChannelId(channel.getChannelId());
				}else{
					vo.setHasChildren(true);
					Floor floor = floorClient.getById(channel.getFloorId());
					vo.setId(floor.getId());
					vo.setLabel(floor.getName());
					vo.setParentId(parentId);
				}
				treeVOList.add(vo);
			}
		}else if(parentColumn.equals("floor")){
			LambdaQueryWrapper<GbDeviceChannel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
			lambdaQueryWrapper.eq(GbDeviceChannel::getFloorId, parentId);
			List<GbDeviceChannel> channelList = list(lambdaQueryWrapper);
			for(GbDeviceChannel gbDeviceChannel : channelList){
				GbDeviceChannelTreeVO vo = new GbDeviceChannelTreeVO();
				vo.setHasChildren(false);
				vo.setId(gbDeviceChannel.getId());
				vo.setLabel(gbDeviceChannel.getName());
				vo.setParentId(parentId);
				vo.setDeviceId(gbDeviceChannel.getDeviceId());
				vo.setChannelId(gbDeviceChannel.getChannelId());
				treeVOList.add(vo);
			}
		}
		return treeVOList;
	}

	@Override
	public List<GbDeviceChannel> listByAgencyId(Long agencyId) {
		LambdaQueryWrapper<GbDeviceChannel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(GbDeviceChannel::getAgencyId, agencyId);
		return list(lambdaQueryWrapper);
	}

	@Override
	public List<GbDeviceChannel> listByResidentialId(Long agencyId, Long residentialId) {
		LambdaQueryWrapper<GbDeviceChannel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(agencyId != null, GbDeviceChannel::getAgencyId, agencyId);
		lambdaQueryWrapper.eq(GbDeviceChannel::getResidentialId, residentialId);
		return list(lambdaQueryWrapper);
	}

	@Override
	public List<GbDeviceChannel> listByBuildingId(Long agencyId, Long residentialId, Long buildingId) {
		LambdaQueryWrapper<GbDeviceChannel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(agencyId != null, GbDeviceChannel::getAgencyId, agencyId);
		lambdaQueryWrapper.eq(residentialId != null,GbDeviceChannel::getResidentialId, residentialId);
		lambdaQueryWrapper.eq(GbDeviceChannel::getBuildingId, buildingId);
		return list(lambdaQueryWrapper);
	}

	@Override
	public List<GbDeviceChannel> listByFloorId(Long agencyId, Long residentialId, Long buildingId, Long floorId) {
		LambdaQueryWrapper<GbDeviceChannel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(agencyId != null, GbDeviceChannel::getAgencyId, agencyId);
		lambdaQueryWrapper.eq(residentialId != null, GbDeviceChannel::getResidentialId, residentialId);
		lambdaQueryWrapper.eq(buildingId != null,GbDeviceChannel::getBuildingId, buildingId);
		lambdaQueryWrapper.eq(GbDeviceChannel::getFloorId, floorId);
		return list(lambdaQueryWrapper);
	}

	@Override
	public R bind(String deviceId, String channelId, Long residentialId, Long buildingId, Long floorId, String installAddress) {
		GbDeviceChannel channel = getByChannelId(deviceId, channelId);
		Assert.notNull(channel, "设备通道不存在");
		channel.setResidentialId(residentialId);
		channel.setBuildingId(buildingId);
		channel.setFloorId(floorId);
		channel.setInstallAddress(installAddress);
		return R.status(updateById(channel));
	}

	@Override
	public R deleteChannel(String deviceId, String tenantId) {
		int i = this.baseMapper.deleteChannel(deviceId, tenantId);
		return R.status(i > 0);
	}

}
