package org.springblade.app.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springblade.app.vo.*;
import org.springblade.common.constant.DeviceConstant;
import org.springblade.community.entity.Agency;
import org.springblade.community.entity.Building;
import org.springblade.community.feign.IAgencyClient;
import org.springblade.community.feign.IBuildingClient;
import org.springblade.community.feign.IResidentialClient;
import org.springblade.community.vo.BuildingVO;
import org.springblade.community.vo.ResidentialVO;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.tool.api.R;
import org.springblade.device.entity.ElectricMeterRecord;
import org.springblade.device.entity.ElectricMeterStatic;
import org.springblade.device.entity.IotDevice;
import org.springblade.device.feign.IElectricMeterRecordClient;
import org.springblade.device.feign.IElectricMeterStaticClient;
import org.springblade.device.feign.IIotDeviceClient;
import org.springblade.device.vo.ElectricMeterRecordVO;
import org.springblade.device.vo.ElectricMeterStaticVO;
import org.springblade.device.vo.IotDeviceVO;
import org.springblade.enterprise.entity.Enterprise;
import org.springblade.enterprise.entity.Staff;
import org.springblade.enterprise.feign.IEnterpriseClient;
import org.springblade.enterprise.feign.IStaffClient;
import org.springblade.enterprise.vo.EnterpriseVO;
import org.springblade.estate.feign.IAccessRecordClient;
import org.springblade.estate.feign.ICarEnterRecordClient;
import org.springblade.estate.feign.ICarOutRecordClient;
import org.springblade.estate.vo.AccessRecordVO;
import org.springblade.estate.vo.CarEnterRecordVO;
import org.springblade.estate.vo.CarOutRecordVO;

import org.springblade.workorder.deviceorder.dto.DeviceOrderDTO;
import org.springblade.workorder.deviceorder.entity.DeviceOrder;
import org.springblade.workorder.deviceorder.feign.IDeviceOrderClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import java.time.LocalDate;
import java.util.*;

/**
 * @author lidexi
 * @date 2021/5/17 18:34
 */

@RestController
@RequiredArgsConstructor
@RequestMapping("/statistics")
public class StaticController {

	private final IAgencyClient agencyClient;
	private final IResidentialClient residentialClient;
	private final IBuildingClient buildingClient;
	private final IIotDeviceClient iotDeviceClient;
	private final IEnterpriseClient enterpriseClient;
	private final IStaffClient staffClient;
	private final IAccessRecordClient accessRecordClient;
	private final ICarEnterRecordClient carEnterRecordClient;
	private final ICarOutRecordClient carOutRecordClient;
	private final RedisTemplate<String,String> redisTemplate;
	private final IElectricMeterStaticClient electricMeterStaticClient;
	private final IElectricMeterRecordClient electricMeterRecordClientl;
	private final IDeviceOrderClient deviceOrderClient;

	/**
	 * 园区态势页面统计
	 */
	@GetMapping("/agency")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "园区态势统计")
	@Transactional
	@ApiIgnore
	public AgencyStatistics agency(Agency agency, BladeUser bladeUser) {
//		String redisKey ="screen:"+ RedisConstant.AGENCY+":"+agency.getId();

		Agency agencyById = this.agencyClient.getById(agency.getId());
		Assert.notNull(agencyById, "该园区不存在");
		AgencyStatistics agencyStatistics = new AgencyStatistics();
		Map<String, Object> searchResidential = new HashMap<>();
		searchResidential.put("agencyId", agencyById.getId());
		List<ResidentialVO> residentials = this.residentialClient.list(searchResidential);
		agencyStatistics.setResidentials(residentials);

		//楼栋
		Building building = new Building();
		building.setAgencyId(agencyById.getId());
		List<BuildingVO> buildingVOS = this.buildingClient.list(building);
		// 楼宇数
		agencyStatistics.setBuildingCount(buildingVOS.size());


//		设备状态1 正常 2 告警 3失联 4 停用(弃用) 5待布防

		//正常设备
		IotDevice searchIotDeviceByStatus = new IotDevice();
		searchIotDeviceByStatus.setDeviceStatus(DeviceConstant.DeviceStatus.NORMAL.getValue());
		Integer safetyCount = this.iotDeviceClient.list(searchIotDeviceByStatus).size();
		agencyStatistics.setSafetyDeviceCount(safetyCount);

		//警告设备
		searchIotDeviceByStatus.setDeviceStatus(DeviceConstant.DeviceStatus.ALARM.getValue());

		Integer warningDeviceCount = this.iotDeviceClient.list(searchIotDeviceByStatus).size();
		agencyStatistics.setWarningDeviceCount(warningDeviceCount);

		//失联设备
		searchIotDeviceByStatus.setDeviceStatus(DeviceConstant.DeviceStatus.MISSING.getValue());
		Integer missingDeviceCount = this.iotDeviceClient.list(searchIotDeviceByStatus).size();
		agencyStatistics.setWarningDeviceCount(missingDeviceCount);

		//停用设备
		searchIotDeviceByStatus.setDeviceStatus(DeviceConstant.DeviceStatus.ABANDON.getValue());
		Integer stopUseDeviceCount = this.iotDeviceClient.list(searchIotDeviceByStatus).size();
		agencyStatistics.setWarningDeviceCount(stopUseDeviceCount);

		//待布防设备
		searchIotDeviceByStatus.setDeviceStatus(DeviceConstant.DeviceStatus.DAIBUFANG.getValue());
		Integer tobeDefendDeviceCount = this.iotDeviceClient.list(searchIotDeviceByStatus).size();
		agencyStatistics.setWarningDeviceCount(tobeDefendDeviceCount);


		//企业列表
		List<EnterpriseVO> enterpriseList = this.enterpriseClient.list(new Enterprise());
		agencyStatistics.setEnterpriseList(enterpriseList);
		agencyStatistics.setEnterpriseCount(enterpriseList.size());
		//员工数
		Staff searchEs = new Staff();
		searchEs.setAgencyId(agencyById.getId());
		Integer staffCount = this.staffClient.list(searchEs).size();
		agencyStatistics.setStaffCount(staffCount);

		return agencyStatistics;
	}

	/**
	 * 	园区当日动态数据
	 * */
	@GetMapping("/todayData")
	@ApiOperation("园区当日动态数据")
	public R<ParkTodayDataVO> todayData(@RequestParam("tenantId") String tenantId,
										@RequestParam(value = "agencyId",required = false) String agencyId,
										@RequestParam(value = "enterpriseId",required = false) String enterpriseId,
										@RequestParam(value = "residentialId",required = false) String residentialId){

		AccessRecordVO accessRecord = new AccessRecordVO();
		accessRecord.setAgencyId(agencyId != null ? Long.valueOf(agencyId) :null);

		accessRecord.setResidentialId(residentialId != null ?Long.valueOf(residentialId): null);
		accessRecord.setEnterpriseId(enterpriseId != null ? Long.valueOf(enterpriseId) : null);
		//内部车出场记录
		CarOutRecordVO carOutRecordInside = new CarOutRecordVO();
		carOutRecordInside.setAgencyId(agencyId != null ? Long.valueOf(agencyId) : null);
		carOutRecordInside.setResidentialId(residentialId != null ? Long.valueOf(residentialId) : null);
		carOutRecordInside.setEnterpriseId(enterpriseId != null ? Long.valueOf(enterpriseId) : null);
		carOutRecordInside.setOutSide(false);
		//内部车入场记录
		CarEnterRecordVO carEnterRecordInside = new CarEnterRecordVO();
		carEnterRecordInside.setAgencyId(agencyId != null ? Long.valueOf(agencyId) : null);
		carEnterRecordInside.setResidentialId(residentialId != null ? Long.valueOf(residentialId) : null);
		carEnterRecordInside.setEnterpriseId(enterpriseId != null ? Long.valueOf(enterpriseId) : null);
		carEnterRecordInside.setOutSide(false);
		//外部车出场记录
		CarOutRecordVO carOutRecordOutside = new CarOutRecordVO();
		carOutRecordOutside.setAgencyId(agencyId != null ? Long.valueOf(agencyId) : null);
		carOutRecordOutside.setResidentialId(residentialId != null ? Long.valueOf(residentialId) : null);
		carOutRecordOutside.setEnterpriseId(enterpriseId != null ? Long.valueOf(enterpriseId) : null);
		carOutRecordOutside.setOutSide(true);
		//外部车入场记录
		CarEnterRecordVO carEnterRecordOutSide = new CarEnterRecordVO();
		carEnterRecordOutSide.setAgencyId(agencyId != null ? Long.valueOf(agencyId) : null);
		carEnterRecordOutSide.setResidentialId(residentialId != null ? Long.valueOf(residentialId) : null);
		carEnterRecordOutSide.setEnterpriseId(enterpriseId != null ? Long.valueOf(enterpriseId) : null);
		carEnterRecordOutSide.setOutSide(true);
		ParkTodayDataVO result = new ParkTodayDataVO.ParkTodayDataVOBuilder()
			.withPeopleNum(accessRecordClient.count(accessRecord))
			.withDepartCarOfInside(carOutRecordClient.count(carOutRecordInside))
			.withDepartCarOfOutside(carOutRecordClient.count(carOutRecordOutside))
			.withEnterCarOfInside(carEnterRecordClient.count(carEnterRecordInside))
			.withEnterCarOfOutside(carEnterRecordClient.count(carEnterRecordOutSide))
			.build();
		return R.data(result);
	}

	/**
	 * 	园区车辆出入趋势
	 * */
	@GetMapping("/carTendency")
	@ApiOperation("园区车辆出入趋势")
	public R<CarTendencyVO> carTendency(@RequestParam("tenantId") String tenantId,
										@RequestParam(value = "agencyId",required = false) String agencyId,
										@RequestParam(value = "enterpriseId",required = false) String enterpriseId,
										@RequestParam(value = "residentialId",required = false) String residentialId){
		/*获取近5日日期列表*/
		Date today = new Date();
		List<String> dateList = new ArrayList<>();
		dateList.add(DateUtil.formatDate(today));
		dateList.add(DateUtil.formatDate(DateUtil.offsetDay(today,-1)));
		dateList.add(DateUtil.formatDate(DateUtil.offsetDay(today,-2)));
		dateList.add(DateUtil.formatDate(DateUtil.offsetDay(today,-3)));
		dateList.add(DateUtil.formatDate(DateUtil.offsetDay(today,-4)));

		/*获取近5日车辆出入记录*/
		//内部进场车辆
		List<Integer> enterCarOfInside = new ArrayList<>();
		//外部进场车辆
		List<Integer> enterCarOfOutside = new ArrayList<>();
		//内部出场车辆
		List<Integer> departCarOfInside = new ArrayList<>();
		//外部出场车辆
		List<Integer> departCarOfOutside = new ArrayList<>();
		//人员出入记录
		List<Integer> peopleNumList = new ArrayList<>();


		AccessRecordVO accessRecord = new AccessRecordVO();
		accessRecord.setAgencyId(agencyId != null ? Long.valueOf(agencyId) :null);

		accessRecord.setResidentialId(residentialId != null ?Long.valueOf(residentialId): null);
		accessRecord.setEnterpriseId(enterpriseId != null ? Long.valueOf(enterpriseId) : null);
		//内部车出场记录
		CarOutRecordVO carOutRecordInside = new CarOutRecordVO();
		carOutRecordInside.setAgencyId(agencyId != null ? Long.valueOf(agencyId) : null);
		carOutRecordInside.setResidentialId(residentialId != null ? Long.valueOf(residentialId) : null);
		carOutRecordInside.setEnterpriseId(enterpriseId != null ? Long.valueOf(enterpriseId) : null);
		carOutRecordInside.setOutSide(false);
		//内部车入场记录
		CarEnterRecordVO carEnterRecordInside = new CarEnterRecordVO();
		carEnterRecordInside.setAgencyId(agencyId != null ? Long.valueOf(agencyId) : null);
		carEnterRecordInside.setResidentialId(residentialId != null ? Long.valueOf(residentialId) : null);
		carEnterRecordInside.setEnterpriseId(enterpriseId != null ? Long.valueOf(enterpriseId) : null);
		carEnterRecordInside.setOutSide(false);
		//外部车出场记录
		CarOutRecordVO carOutRecordOutside = new CarOutRecordVO();
		carOutRecordOutside.setAgencyId(agencyId != null ? Long.valueOf(agencyId) : null);
		carOutRecordOutside.setResidentialId(residentialId != null ? Long.valueOf(residentialId) : null);
		carOutRecordOutside.setEnterpriseId(enterpriseId != null ? Long.valueOf(enterpriseId) : null);
		carOutRecordOutside.setOutSide(true);
		//外部车入场记录
		CarEnterRecordVO carEnterRecordOutSide = new CarEnterRecordVO();
		carEnterRecordOutSide.setAgencyId(agencyId != null ? Long.valueOf(agencyId) : null);
		carEnterRecordOutSide.setResidentialId(residentialId != null ? Long.valueOf(residentialId) : null);
		carEnterRecordOutSide.setEnterpriseId(enterpriseId != null ? Long.valueOf(enterpriseId) : null);
		carEnterRecordOutSide.setOutSide(true);
		/*并行流获取各日期数据*/
		dateList.stream().forEach(item -> {
			enterCarOfInside.add(carEnterRecordClient.count(carEnterRecordInside));
			enterCarOfOutside.add(carEnterRecordClient.count(carEnterRecordOutSide));
			departCarOfInside.add(carOutRecordClient.count(carOutRecordInside));
			departCarOfOutside.add(carOutRecordClient.count(carOutRecordOutside));
			accessRecord.setCreateTimeLike(item);
			peopleNumList.add( accessRecordClient.count(accessRecord));
		});

		return R.data(
			new CarTendencyVO.CarTendencyVOBuilder()
				.withDateList(dateList)
				.withDepartCarOfInside(departCarOfInside)
				.withDepartCarOfOutside(departCarOfOutside)
				.withEnterCarOfInside(enterCarOfInside)
				.withEnterCarOfOutside(enterCarOfOutside)
				.withPeopleNUm(peopleNumList)
				.build()
		);
	}


	@ApiOperation(value = "电表大屏统计", notes = "传入agencyId(园区id)")
	@GetMapping("/electricMeterStatic")
	public R<ElectricMeterStaticVO> getStaticOf30Day(Long agencyId){
		Agency agency = agencyClient.getById(agencyId);
		if(null == agency){
			return R.fail("agencyId对应的实体不存在");
		}
		String data = redisTemplate.opsForValue().get("ycwg:electricstatic:"+agencyId);
		ElectricMeterStaticVO electricMeterStaticVO;
		if(data != null){
			electricMeterStaticVO = JSON.parseObject(data, ElectricMeterStaticVO.class);
		}else {

			electricMeterStaticVO = new ElectricMeterStaticVO();
			List<String> dates = this.getDates();
			List<String> dayValues = new ArrayList<>();
			for(int i=0;i<dates.size();i++){
				ElectricMeterStatic search = new ElectricMeterStatic();
				search.setDate(dates.get(i));
				search.setAgencyId(agencyId);
				ElectricMeterStatic electricMeterStatic = electricMeterStaticClient.detail(search);
				if(null != electricMeterStatic){
					dayValues.add(electricMeterStatic.getDayValue());
				}else {
					ElectricMeterStatic newObj = new ElectricMeterStatic();
					newObj.setAgencyId(agencyId);
					newObj.setDate(dates.get(i));

					//查询当前查询日期该园区用电总量
					ElectricMeterRecord searchEntity = new ElectricMeterRecord();
					searchEntity.setReadTime(dates.get(i));
					List<ElectricMeterRecordVO> electricMeterRecords = electricMeterRecordClientl.list(searchEntity);
					double daySum = electricMeterRecords.stream().mapToDouble(e -> Double.parseDouble(e.getDayValue())).sum();
					double monthSum = electricMeterRecords.stream().mapToDouble(e -> Double.parseDouble(e.getDayValue())).sum();
					double yearSum = electricMeterRecords.stream().mapToDouble(e -> Double.parseDouble(e.getDayValue())).sum();
					dayValues.add(String.valueOf(daySum));

					newObj.setDayValue(String.valueOf(daySum));
					newObj.setMonthValue(String.valueOf(monthSum));
					newObj.setYearValue(String.valueOf(yearSum));
					this.electricMeterStaticClient.save(newObj);
				}
			}


			electricMeterStaticVO.setDates(dates);
			electricMeterStaticVO.setValues(dayValues);

			redisTemplate.opsForValue().set("ycwg:electricstatic:"+agencyId,JSON.toJSONString(electricMeterStaticVO));
		}
		return  R.data(electricMeterStaticVO);
	}

	@ApiOperation(value = "园区小程序获取消防设备统计")
	@GetMapping("/getFireStatic")
	public R<FireStaticVO> getFireStatic(BladeUser bladeUser){
		FireStaticVO fireStaticVO = new FireStaticVO();

		//烟感设备总数
		IotDevice searchEntity = new IotDevice();
		searchEntity.setTenantId(bladeUser.getTenantId());
		List<IotDevice> smokeDevices = iotDeviceClient.getSmokeDeviceList(searchEntity);


		fireStaticVO.setSmokeAmount(smokeDevices.size());
		Long smokeNormal = smokeDevices.stream().filter(
			smartDevice -> DeviceConstant.DeviceStatus.NORMAL.getValue()==smartDevice.getDeviceStatus()
		).count();
		fireStaticVO.setSmokeNormal(Math.toIntExact(smokeNormal));
		fireStaticVO.setSmokeException(fireStaticVO.getSmokeAmount()-fireStaticVO.getSmokeNormal());

		//消防栓设备总数
		IotDevice hydrant = new IotDevice();
		hydrant.setDeviceType("XFS");
		hydrant.setTenantId(bladeUser.getTenantId());
		List<IotDeviceVO> hydrantDevices = iotDeviceClient.list(hydrant);

		fireStaticVO.setHydrantAmount(hydrantDevices.size());
		Long hydrantNormal = hydrantDevices.stream().filter(
			hydrantDevice -> DeviceConstant.DeviceStatus.NORMAL.getValue()==hydrantDevice.getDeviceStatus()
		).count();
		fireStaticVO.setHydrantNormal(Math.toIntExact(hydrantNormal));
		fireStaticVO.setHydrantException(fireStaticVO.getHydrantAmount()-fireStaticVO.getHydrantNormal());

		//燃气设备总数
		IotDevice gasDevice = new IotDevice();
		gasDevice.setTenantId(bladeUser.getTenantId());
		List<IotDevice> gasDevices = iotDeviceClient.getGasDeviceList(gasDevice);

		fireStaticVO.setGasAmount(gasDevices.size());
		Long gasNormal = gasDevices.stream().filter(gas -> DeviceConstant.DeviceStatus.NORMAL.getValue()==gas.getDeviceStatus()).count();
		fireStaticVO.setGasNormal(Math.toIntExact(gasNormal));
		fireStaticVO.setGasException(fireStaticVO.getGasAmount()-fireStaticVO.getGasNormal());


		return R.data(fireStaticVO);
	}

	@ApiOperation("园区小程序获取消防场景告警工单统计")
	@GetMapping("/getDeviceJobStaticByApp")
	public R<DeviceJobStaticVO> getDeviceJobStaticByApp(BladeUser bladeUser){
		DeviceJobStaticVO deviceJobStaticVO = new DeviceJobStaticVO();

		List<Integer> deviceTypeList = new ArrayList<>();
		deviceTypeList.add(DeviceConstant.DeviceType.SMOKE.getValue());
		deviceTypeList.add(DeviceConstant.DeviceType.SMOKE_MODEL.getValue());
		deviceTypeList.add(DeviceConstant.DeviceType.HYDRANT.getValue());
		deviceTypeList.add(DeviceConstant.DeviceType.GAS.getValue());
		deviceTypeList.add(DeviceConstant.DeviceType.GAS_MODEL.getValue());

		DeviceOrderDTO deviceOrderDTO = new DeviceOrderDTO();
		deviceOrderDTO.setDeviceTypeList(deviceTypeList);
		deviceOrderDTO.setTenantId(bladeUser.getTenantId());
		List<DeviceOrder> deviceJobs = deviceOrderClient.getListByDeviceTypeList(deviceOrderDTO);


		deviceJobStaticVO.setDeviceJobAmount(deviceJobs.size());
		long finish = deviceJobs.stream().filter(deviceJob -> 2 == deviceJob.getJobStatus()).count();
		deviceJobStaticVO.setResolvedAmount(Math.toIntExact(finish));
		deviceJobStaticVO.setResolvingAmount(deviceJobStaticVO.getDeviceJobAmount()-deviceJobStaticVO.getResolvedAmount());

		return R.data(deviceJobStaticVO);
	}


	private List<String> getDates() {
		List<String> dateList = new ArrayList<>();
		String dates = redisTemplate.opsForValue().get("ycwg:electricstatic:dates");
		if (dates == null) {
			dateList.add(LocalDate.now().plusDays(-30).toString());
			dateList.add(LocalDate.now().plusDays(-29).toString());
			dateList.add(LocalDate.now().plusDays(-28).toString());
			dateList.add(LocalDate.now().plusDays(-27).toString());
			dateList.add(LocalDate.now().plusDays(-26).toString());
			dateList.add(LocalDate.now().plusDays(-25).toString());
			dateList.add(LocalDate.now().plusDays(-24).toString());
			dateList.add(LocalDate.now().plusDays(-23).toString());
			dateList.add(LocalDate.now().plusDays(-22).toString());
			dateList.add(LocalDate.now().plusDays(-21).toString());
			dateList.add(LocalDate.now().plusDays(-20).toString());
			dateList.add(LocalDate.now().plusDays(-19).toString());
			dateList.add(LocalDate.now().plusDays(-18).toString());
			dateList.add(LocalDate.now().plusDays(-17).toString());
			dateList.add(LocalDate.now().plusDays(-16).toString());
			dateList.add(LocalDate.now().plusDays(-15).toString());
			dateList.add(LocalDate.now().plusDays(-14).toString());
			dateList.add(LocalDate.now().plusDays(-13).toString());
			dateList.add(LocalDate.now().plusDays(-12).toString());
			dateList.add(LocalDate.now().plusDays(-11).toString());
			dateList.add(LocalDate.now().plusDays(-10).toString());
			dateList.add(LocalDate.now().plusDays(-9).toString());
			dateList.add(LocalDate.now().plusDays(-8).toString());
			dateList.add(LocalDate.now().plusDays(-7).toString());
			dateList.add(LocalDate.now().plusDays(-6).toString());
			dateList.add(LocalDate.now().plusDays(-5).toString());
			dateList.add(LocalDate.now().plusDays(-4).toString());
			dateList.add(LocalDate.now().plusDays(-3).toString());
			dateList.add(LocalDate.now().plusDays(-2).toString());
			dateList.add(LocalDate.now().plusDays(-1).toString());
			redisTemplate.opsForValue().set("ycwg:electricstatic:dates", JSON.toJSONString(dateList));
		} else {
			dateList = JSON.parseObject(dates, ArrayList.class);
		}
		return dateList;
	}


}
