package com.qiuguo.iot.data.service.device;


import com.alibaba.fastjson.JSONObject;
import com.qiuguo.iot.base.utils.StringUtils;
import com.qiuguo.iot.data.entity.device.DeviceUserBindEntity;
import com.qiuguo.iot.data.request.device.DeviceUserBindRequest;
import com.qiuguo.iot.data.resp.device.DeviceUserBindResp;
import lombok.extern.slf4j.Slf4j;
import org.hswebframework.ezorm.core.param.Sort;
import org.hswebframework.ezorm.core.param.Term;
import org.hswebframework.ezorm.rdb.executor.wrapper.ListResultWrapper;
import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper;
import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrappers;
import org.hswebframework.ezorm.rdb.mapping.ReactiveQuery;
import org.hswebframework.ezorm.rdb.mapping.ReactiveUpdate;
import org.hswebframework.ezorm.rdb.mapping.events.EventSupportWrapper;
import org.hswebframework.ezorm.rdb.mapping.wrapper.EntityResultWrapper;
import org.hswebframework.ezorm.rdb.metadata.RDBDatabaseMetadata;
import org.hswebframework.ezorm.rdb.operator.DatabaseOperator;
import org.hswebframework.ezorm.rdb.operator.DefaultDatabaseOperator;
import org.hswebframework.ezorm.rdb.operator.dml.QueryOperator;
import org.hswebframework.ezorm.rdb.operator.dml.delete.DeleteOperator;
import org.hswebframework.ezorm.rdb.operator.dml.query.SelectColumn;
import org.hswebframework.ezorm.rdb.operator.dml.query.SortOrder;
import org.hswebframework.ezorm.rdb.supports.mysql.MysqlDialect;
import org.hswebframework.ezorm.rdb.supports.mysql.MysqlSchemaMetadata;
import org.hswebframework.web.api.crud.entity.PagerResult;
import org.hswebframework.web.api.crud.entity.QueryParamEntity;
import org.hswebframework.web.crud.service.GenericReactiveCrudService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.*;

/**
* <p>
* 设备与用户绑定服务类
* </p>
*
* @author wulin
* @since 2023-08-08
*/

@Service
@Slf4j
public class DeviceUserBindService extends GenericReactiveCrudService<DeviceUserBindEntity, Long> {

	@Autowired
	private DatabaseOperator databaseOperator;



	public Mono<DeviceUserBindEntity> selectDeviceUserBindByRequest(DeviceUserBindRequest request){
		ReactiveQuery<DeviceUserBindEntity> reactiveQuery = createQuery();
		reactiveQuery = reactiveQuery.and("is_delete", 0);
		if(request.getId() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getId, request.getId());
		}
		if(request.getIsDelete() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getIsDelete, request.getIsDelete());
		}
		if(request.getCreateTime() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getCreateTime, request.getCreateTime());
		}
		if(request.getModifyTime() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getModifyTime, request.getModifyTime());
		}
		if(request.getIsBind() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getIsBind, request.getIsBind());
		}
		if(request.getUserId() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getUserId, request.getUserId());
		}
		if(request.getDeviceType() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getDeviceType, request.getDeviceType());
		}
		if(request.getDeviceId() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getDeviceId, request.getDeviceId());
		}
		if(request.getOtherDeviceId() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getOtherDeviceId, request.getOtherDeviceId());
		}
		if(request.getSpaceId() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getSpaceId, request.getSpaceId());
		}
		if(request.getIsMain() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getIsMain, request.getIsMain());
		}
		if(StringUtils.isNotEmpty(request.getBindName())){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getBindName, request.getBindName());
		}
		if(StringUtils.isNotEmpty(request.getCountry())){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getCountry, request.getCountry());
		}
		if(StringUtils.isNotEmpty(request.getProvince())){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getProvince, request.getProvince());
		}
		if(StringUtils.isNotEmpty(request.getCity())){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getCity, request.getCity());
		}
		if(StringUtils.isNotEmpty(request.getCounty())){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getCounty, request.getCounty());
		}
		if(StringUtils.isNotEmpty(request.getVillage())){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getVillage, request.getVillage());
		}
		if(StringUtils.isNotEmpty(request.getAddress())){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getAddress, request.getAddress());
		}
		if(StringUtils.isNotEmpty(request.getCategoryCode())){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getCategoryCode, request.getCategoryCode());
		}
		SortOrder sortOrder = null;
		if(StringUtils.isNotEmpty(request.getOrder())){
			if(StringUtils.isNotEmpty(request.getSort()) && request.getSort().compareTo("0") == 0){
				sortOrder = SortOrder.desc(request.getOrder());
			}else{
				sortOrder = SortOrder.asc(request.getOrder());
			}
			reactiveQuery = reactiveQuery.orderBy(sortOrder);
		}
		return reactiveQuery.fetchOne();
	}



	public Mono<PagerResult<DeviceUserBindEntity>> selectDeviceUserBindsByRequest(DeviceUserBindRequest request){

		return queryPager(getSelectParamter(request));
	}

	private QueryParamEntity getSelectParamter(DeviceUserBindRequest request){
		ReactiveQuery<DeviceUserBindEntity> reactiveQuery = createQuery();
		reactiveQuery = reactiveQuery.and("is_delete", 0);
		if(request.getId() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getId, request.getId());
		}
		if(request.getIsDelete() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getIsDelete, request.getIsDelete());
		}
		if(request.getCreateTimeStart() != null){
			reactiveQuery = reactiveQuery.gte(DeviceUserBindRequest::getCreateTime, request.getCreateTimeStart());
		}
		if(request.getCreateTimeEnd() != null){
			reactiveQuery = reactiveQuery.lte(DeviceUserBindRequest::getCreateTime, request.getCreateTimeEnd());
		}
		if(request.getModifyTimeStart() != null){
			reactiveQuery = reactiveQuery.gte(DeviceUserBindRequest::getModifyTime, request.getModifyTimeStart());
		}
		if(request.getModifyTimeEnd() != null){
			reactiveQuery = reactiveQuery.lte(DeviceUserBindRequest::getModifyTime, request.getModifyTimeEnd());
		}
		if(request.getUserId() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getUserId, request.getUserId());
		}
		if(request.getIsBind() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getIsBind, request.getIsBind());
		}
		if(request.getDeviceType() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getDeviceType, request.getDeviceType());
		}
		if(request.getDeviceId() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getDeviceId, request.getDeviceId());
		}
		if(request.getOtherDeviceId() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getOtherDeviceId, request.getOtherDeviceId());
		}
		if(request.getSpaceId() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getSpaceId, request.getSpaceId());
		}
		if(request.getIsMain() != null){
			reactiveQuery = reactiveQuery.and(DeviceUserBindRequest::getIsMain, request.getIsMain());
		}
		if(StringUtils.isNotEmpty(request.getBindName())){
			reactiveQuery = reactiveQuery.$like$(DeviceUserBindRequest::getBindName, request.getBindName());
		}
		if(StringUtils.isNotEmpty(request.getCountry())){
			reactiveQuery = reactiveQuery.$like$(DeviceUserBindRequest::getCountry, request.getCountry());
		}
		if(StringUtils.isNotEmpty(request.getProvince())){
			reactiveQuery = reactiveQuery.$like$(DeviceUserBindRequest::getProvince, request.getProvince());
		}
		if(StringUtils.isNotEmpty(request.getCity())){
			reactiveQuery = reactiveQuery.$like$(DeviceUserBindRequest::getCity, request.getCity());
		}
		if(StringUtils.isNotEmpty(request.getCounty())){
			reactiveQuery = reactiveQuery.$like$(DeviceUserBindRequest::getCounty, request.getCounty());
		}
		if(StringUtils.isNotEmpty(request.getVillage())){
			reactiveQuery = reactiveQuery.$like$(DeviceUserBindRequest::getVillage, request.getVillage());
		}
		if(StringUtils.isNotEmpty(request.getAddress())){
			reactiveQuery = reactiveQuery.$like$(DeviceUserBindRequest::getAddress, request.getAddress());
		}
		if(StringUtils.isNotEmpty(request.getCategoryCode())){
			reactiveQuery = reactiveQuery.$like$(DeviceUserBindRequest::getCategoryCode, request.getCategoryCode());
		}
		QueryParamEntity param = QueryParamEntity.of(reactiveQuery.getParam());
		if(StringUtils.isNotEmpty(request.getOrder())){
			Sort sort = new Sort();
			sort.setName(request.getOrder());
			if(StringUtils.isNotEmpty(request.getSort()) && request.getSort().compareTo("0") == 0){
				sort.desc();
			}else{
				sort.asc();
			}
			param.setSorts(Arrays.asList(sort));
		}
		param.setPageIndex(request.getCurrPage());
		param.setPageSize(request.getPageSize());
		param.setPaging(true);
		param.setFirstPageIndex(1);
		return param;
	}



	public Mono<DeviceUserBindEntity> selectDeviceUserBindById(Long id){
		return createQuery()
				.and("is_delete", 0)
				.and("id", id)
				.fetchOne();
	}



	public Mono<Integer> insertDeviceUserBind(DeviceUserBindEntity entity){
		entity.setId(null);
		entity.setCreateTime(null);
		entity.setModifyTime(null);
		return insert(entity);
	}



	public Mono<Integer> updateDeviceUserBindById(DeviceUserBindEntity entity){
		ReactiveUpdate<DeviceUserBindEntity> update = createUpdate()
				.set(DeviceUserBindEntity::getModifyTime, new Date());
		if(entity.getIsDelete() != null){
			update = update.set(DeviceUserBindEntity::getIsDelete, entity.getIsDelete());
		}
		if(entity.getIsBind() != null){
			update = update.set(DeviceUserBindEntity::getIsBind, entity.getIsBind());
		}
		if(entity.getUserId() != null){
			update = update.set(DeviceUserBindEntity::getUserId, entity.getUserId());
		}
		if(entity.getDeviceType() != null){
			update = update.set(DeviceUserBindEntity::getDeviceType, entity.getDeviceType());
		}
		if(entity.getDeviceId() != null){
			update = update.set(DeviceUserBindEntity::getDeviceId, entity.getDeviceId());
		}
		if(entity.getOtherDeviceId() != null){
			update = update.set(DeviceUserBindEntity::getOtherDeviceId, entity.getOtherDeviceId());
		}
		if(entity.getSpaceId() != null){
			update = update.set(DeviceUserBindEntity::getSpaceId, entity.getSpaceId());
		}
		if(entity.getIsMain() != null){
			update = update.set(DeviceUserBindEntity::getIsMain, entity.getIsMain());
		}
		if(StringUtils.isNotEmpty(entity.getBindName())){
			update = update.set(DeviceUserBindEntity::getBindName, entity.getBindName());
		}
		if(StringUtils.isNotEmpty(entity.getCountry())){
			update = update.set(DeviceUserBindEntity::getCountry, entity.getCountry());
		}
		if(StringUtils.isNotEmpty(entity.getProvince())){
			update = update.set(DeviceUserBindEntity::getProvince, entity.getProvince());
		}
		if(StringUtils.isNotEmpty(entity.getCity())){
			update = update.set(DeviceUserBindEntity::getCity, entity.getCity());
		}
		if(StringUtils.isNotEmpty(entity.getCounty())){
			update = update.set(DeviceUserBindEntity::getCounty, entity.getCounty());
		}
		if(StringUtils.isNotEmpty(entity.getVillage())){
			update = update.set(DeviceUserBindEntity::getVillage, entity.getVillage());
		}
		if(StringUtils.isNotEmpty(entity.getAddress())){
			update = update.set(DeviceUserBindEntity::getAddress, entity.getAddress());
		}
		if(StringUtils.isNotEmpty(entity.getCategoryCode())){
			update = update.set(DeviceUserBindEntity::getCategoryCode, entity.getCategoryCode());
		}
		return update.where(DeviceUserBindEntity::getId, entity.getId()).and("is_delete", 0).execute();
	}



	public Mono<Integer> updateCoverDeviceUserBindById(DeviceUserBindEntity entity){
		ReactiveUpdate<DeviceUserBindEntity> update = createUpdate()
				.set(DeviceUserBindEntity::getModifyTime, new Date());
		update = update.set(DeviceUserBindEntity::getIsDelete, entity.getIsDelete());
		update = update.set(DeviceUserBindEntity::getIsBind, entity.getIsBind());
		update = update.set(DeviceUserBindEntity::getUserId, entity.getUserId());
		update = update.set(DeviceUserBindEntity::getDeviceType, entity.getDeviceType());
		update = update.set(DeviceUserBindEntity::getDeviceId, entity.getDeviceId());
		update = update.set(DeviceUserBindEntity::getOtherDeviceId, entity.getOtherDeviceId());
		update = update.set(DeviceUserBindEntity::getSpaceId, entity.getSpaceId());
		update = update.set(DeviceUserBindEntity::getIsMain, entity.getIsMain());
		update = update.set(DeviceUserBindEntity::getBindName, entity.getBindName());
		update = update.set(DeviceUserBindEntity::getCountry, entity.getCountry());
		update = update.set(DeviceUserBindEntity::getProvince, entity.getProvince());
		update = update.set(DeviceUserBindEntity::getCity, entity.getCity());
		update = update.set(DeviceUserBindEntity::getCounty, entity.getCounty());
		update = update.set(DeviceUserBindEntity::getVillage, entity.getVillage());
		update = update.set(DeviceUserBindEntity::getAddress, entity.getAddress());
		update = update.set(DeviceUserBindEntity::getCategoryCode, entity.getCategoryCode());
		return update.where(DeviceUserBindEntity::getId, entity.getId()).and("is_delete", 0).execute();
	}



	public Mono<Integer> deleteDeviceUserBindById(Long id){
		return createUpdate()
				.set("is_delete", 1)
				.set("modify_time", new Date())
				.where("id", id)
				.execute();
	}

	/***
	 * 设置同类型设备为非主设备
	 * @param userId
	 * @param code
	 */
    public Mono<Integer> setNoMain(Long userId, Integer code) {
		return createUpdate()
				.set("is_main", 0)
				.set("modify_time", new Date())
				.where("user_id", userId)
				.and("is_main", 1)
				.and("is_delete", 0)
				.and("device_type", code)
				.execute();
    }

	/***
	 * 设置同类型设备为主设备
	 * @param userId
	 * @param code
	 */
	public Mono<Integer> setMain(Long userId, Long deviceId, Integer code) {
		return createUpdate()
				.set("is_main", 1)
				.set("modify_time", new Date())
				.where("user_id", userId)
				.and("is_delete", 0)
				.and("is_main", 0)
				.and("device_type", code)
				.and("device_id", deviceId)
				.execute();
	}

	public Mono<PagerResult<DeviceUserBindResp>> selectDeviceUserBindsContainOnLineByRequest(DeviceUserBindRequest request) {
		QueryOperator queryOperator = databaseOperator.dml().query("device_user_bind").setParam(getSelectParamter(request))
				.select(SelectColumn.of("device_user_bind.*"))
				//本表的只能这样，下面的错误
				/*.select(SelectColumn.of("device_user_bind.is_main", "isMain"))
				.select(SelectColumn.of("device_user_bind.other_device_id", "otherDeviceId"))
				.select(SelectColumn.of("device_user_bind.bind_name", "bindName"))
				.select(SelectColumn.of("device_user_bind.city", "city"))
				.select(SelectColumn.of("device_user_bind.device_type", "deviceType"))
				.select(SelectColumn.of("device_user_bind.category_code", "categoryCode"))
				.select(SelectColumn.of("device_user_bind.province", "province"))
				.select(SelectColumn.of("device_user_bind.address", "address"))
				.select(SelectColumn.of("device_user_bind.county", "county"))
				.select(SelectColumn.of("device_user_bind.modify_time", "modifyTime"))
				.select(SelectColumn.of("device_user_bind.id", "id"))
				.select(SelectColumn.of("device_user_bind.village", "village"))
				.select(SelectColumn.of("device_user_bind.space_id", "spaceId"))
				.select(SelectColumn.of("device_user_bind.device_id", "deviceId"))
				.select(SelectColumn.of("device_user_bind.country", "country"))
				.select(SelectColumn.of("device_user_bind.is_delete", "isDelete"))*/
				.select(SelectColumn.of("device_info.last_on_line_time", "lastOnLineTime"))
				.select(SelectColumn.of("device_info.last_off_line_time", "lastOffLineTime"))
				.select(SelectColumn.of("device_info.on_line", "onLine"))
				//.select(SelectColumn.of("count(1)", "total"))
				.leftJoin("device_info", joinOperator -> {
					joinOperator.on("device_user_bind.device_id = device_info.id");
				});
		Term term = new Term();
		term.and("device_info.is_delete", 0);
		if(request.getOnLine() != null){
			term.and("device_info.on_line", request.getOnLine());
		}
		queryOperator.where(term);
		//String sql = queryOperator.getSql().getSql();
		//20231008日记：暂未实现查询总量功能，后期补上

		return queryOperator.fetch(ResultWrappers.mapList()).reactive().map(map ->{
			JSONObject jsonObject = new JSONObject(map);
			DeviceUserBindResp deviceUserBindResp = JSONObject.toJavaObject(jsonObject, DeviceUserBindResp.class);
			return deviceUserBindResp;
		}).collectList().map(list ->{
			PagerResult<DeviceUserBindResp> pagerResult = new PagerResult<>();

			pagerResult.setPageIndex(request.getCurrPage());
			pagerResult.setPageSize(request.getPageSize());
			pagerResult.setTotal(10);
			pagerResult.setData(list);
			return pagerResult;
		});

	}

	public Mono<Integer> UnbindingDevice(Long userId, Long deviceId) {
		return createUpdate()
				.set("is_bind", 0)
				.set("modify_time", new Date())
				.where("user_id", userId)
				.and("is_delete", 0)
				//.and("device_type", code)
				.and("device_id", deviceId)
				.execute();
	}

	public Mono<Integer> updateDeviceUserBind(DeviceUserBindEntity deviceUserBindEntity) {
		return createUpdate().set("modify_time", new Date())
				.set("bind_name", deviceUserBindEntity.getBindName())
				.where("user_id", deviceUserBindEntity.getUserId())
				.and("device_id", deviceUserBindEntity.getDeviceId())
				.and("is_delete", 0)
				.execute();
	}
}
