package cn.iocoder.yudao.module.product.service.envdata;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.basic.api.businessinfo.BusinessInfoApi;
import cn.iocoder.yudao.module.basic.api.redis.dto.BusinessInfoDTO;
import cn.iocoder.yudao.module.configure.api.deviceenvtype.DeviceEnvTypeApi;
import cn.iocoder.yudao.module.configure.api.deviceenvtype.dto.DeviceEnvTypeRespDTO;
import cn.iocoder.yudao.module.product.controller.admin.deviceinfo.vo.DeviceEnvTypeRespVO;
import cn.iocoder.yudao.module.product.controller.admin.envdata.vo.EnvDataCreateReqVO;
import cn.iocoder.yudao.module.product.controller.admin.envdata.vo.EnvDataPageReqVO;
import cn.iocoder.yudao.module.product.controller.admin.envdata.vo.EnvDataRespVO;
import cn.iocoder.yudao.module.product.controller.admin.envdata.vo.EnvDataUpdateReqVO;
import cn.iocoder.yudao.module.product.convert.envdata.EnvDataConvert;
import cn.iocoder.yudao.module.product.dal.dataobject.envdata.EnvDataDO;
import cn.iocoder.yudao.module.product.dal.mysql.deviceinfo.DeviceInfoMapper;
import cn.iocoder.yudao.module.product.dal.mysql.envdata.EnvDataMapper;
import cn.iocoder.yudao.module.product.enums.DeviceTypeEnums;
import cn.iocoder.yudao.module.product.enums.GatewayTypeEnums;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.ENV_DATA_NOT_EXISTS;

/**
 * 环境数据 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class EnvDataServiceImpl implements EnvDataService {

    @Resource
    private EnvDataMapper envDataMapper;

    @Resource
    private DeviceInfoMapper deviceInfoMapper;

    @Resource
    private DeviceEnvTypeApi deviceEnvTypeApi;

    @Resource
    private BusinessInfoApi businessInfoApi;

    @Override
    public Long createEnvData(EnvDataCreateReqVO createReqVO) {
        // 插入
        EnvDataDO envData = EnvDataConvert.INSTANCE.convert(createReqVO);
        envDataMapper.insert(envData);
        // 返回
        return envData.getId();
    }

    @Override
    public void updateEnvData(EnvDataUpdateReqVO updateReqVO) {
        // 校验存在
        validateEnvDataExists(updateReqVO.getId());
        // 更新
        EnvDataDO updateObj = EnvDataConvert.INSTANCE.convert(updateReqVO);
        envDataMapper.updateById(updateObj);
    }

    @Override
    public void deleteEnvData(Long id) {
        // 校验存在
        validateEnvDataExists(id);
        // 删除
        envDataMapper.deleteById(id);
    }

    private void validateEnvDataExists(Long id) {
        if (envDataMapper.selectById(id) == null) {
            throw exception(ENV_DATA_NOT_EXISTS);
        }
    }

    @Override
    public EnvDataDO getEnvData(Long id) {
        return envDataMapper.selectById(id);
    }

    @Override
    public PageResult<EnvDataRespVO> getEnvDataPage(EnvDataPageReqVO pageReqVO) {
        Page<EnvDataRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        List<EnvDataRespVO> result = envDataMapper.selectEnvDataPage(page, pageReqVO);
        return new PageResult<>(result, page.getTotal());
    }

    @Override
    @Transactional
    public void saveEnvDataByEmqx(String topic, String message) {
        if (!topic.contains("/bilian") && !topic.contains("/youren")) {
            return;
        }
        // 首先区分是有人还是必联发过来的传感器数据
        Integer gatewayType = topic.indexOf("/bilian") > 0 ? GatewayTypeEnums.BILIAN.getGatewayType() : GatewayTypeEnums.YOUREN.getGatewayType();
        int paramIndex = topic.indexOf("/", topic.indexOf("/bilian") + 1);
        if (gatewayType.equals(GatewayTypeEnums.YOUREN.getGatewayType())) {
            paramIndex = topic.indexOf("/", topic.indexOf("/youren") + 1);
        }

        if (paramIndex == -1) {
            return;
        }
        String paramStr = topic.substring(paramIndex);
        // 根据主题分割出租户ID，商户ID，地块ID
        String[] slStr = paramStr.split("/");
        if (slStr.length != 4) {
            return;
        }
        Long tenantId = Long.valueOf(slStr[1]);
        Long businessId = Long.valueOf(slStr[2]);

//        TenantUtils.execute(tenantId, () -> {
        TenantContextHolder.setTenantId(tenantId);// 这里手动设置租户ID
        // 模拟租户ID为tenantId的情况下

        // 根据参数获取所有传感器的设备类型
        List<DeviceEnvTypeRespVO> deviceInfos = deviceInfoMapper.getDeviceEnvTypes(tenantId, businessId, DeviceTypeEnums.SENSOR.getDeviceType(), gatewayType);
        if (deviceInfos.isEmpty()) {
            return;
        }
        // 获取商户
        BusinessInfoDTO businessInfo = businessInfoApi.getBusinessInfoById(businessId).getData();
        if (businessInfo == null) {
            return;
        }

        List<EnvDataDO> insertEnvDatas = new ArrayList<>();
        JSONObject jsonObject = JSONObject.parseObject(message);

        // 根据类型字段 从message中获得数据 插入环境数据表
        if (gatewayType.equals(GatewayTypeEnums.YOUREN.getGatewayType())) {
            // 首先循环主表
            deviceInfos.forEach(info -> {
                if (jsonObject.get(info.getEnvFieldName()) != null) {
                    JSONObject infoJson = JSONObject.parseObject(jsonObject.get(info.getEnvFieldName()).toString());
                    // 说明有传入该配置的值，循环子表继续进行查找
                    info.getSlaveEnvTypes().forEach(item -> {
                        String fieldVal = infoJson.getString(item.getEnvFieldName());
                        if (fieldVal != null) {
                            EnvDataDO envDataDO = new EnvDataDO();
                            envDataDO.setEnvTypeId(item.getEnvType());
                            envDataDO.setEnvName(item.getEnvTypeName());
                            envDataDO.setValue(fieldVal);
                            envDataDO.setBelongBusinessId(businessId);
                            envDataDO.setBelongBusinessName(businessInfo.getBusinessName());
                            envDataDO.setTenantId(tenantId);
                            envDataDO.setCreator(tenantId.toString());
                            envDataDO.setUpdater(tenantId.toString());
                            insertEnvDatas.add(envDataDO);
                        }
                    });
                }
            });
        } else {
            // 必联只有主表，注意 这个流程未经过测试！
            deviceInfos.forEach(info -> {
                String fieldVal = jsonObject.getString(info.getEnvFieldName());
                if (fieldVal != null) {
                    EnvDataDO envDataDO = new EnvDataDO();
                    envDataDO.setEnvTypeId(info.getEnvType());
                    envDataDO.setEnvName(info.getEnvTypeName());
                    envDataDO.setValue(fieldVal);
                    envDataDO.setBelongBusinessName(businessInfo.getBusinessName());
                    envDataDO.setBelongBusinessId(tenantId);
                    envDataDO.setTenantId(tenantId);
                    envDataDO.setCreator(tenantId.toString());
                    envDataDO.setUpdater(tenantId.toString());
                    insertEnvDatas.add(envDataDO);
                }
            });
        }

        if (!insertEnvDatas.isEmpty()) {
            envDataMapper.insertBatch(insertEnvDatas);
        }
    }

    @Override
    public List<EnvDataRespVO> gatLastEnvDatas(String landId) {
        EnvDataDO envData = envDataMapper.getLastOne(landId);
        if(envData != null) {
            List<Long> typeIds = this.getConfigEnvTypeIds(landId);
            return envDataMapper.getLastEnvDatas(landId, Date.from(envData.getCreateTime().atZone(ZoneId.systemDefault()).toInstant()), typeIds);
        }
        return new ArrayList<>();
    }

    @Override
    public List<EnvDataRespVO> getAVGEnvDatas(String landId, Integer day, List<Long> typeIds) {
        if(day == null) {
            day = 7;
        }
        if (typeIds == null) {
            typeIds = this.getConfigEnvTypeIds(landId);
        }
        return envDataMapper.getAVGEnvDatas(landId, day, typeIds);
    }

    private List<Long> getConfigEnvTypeIds(String landId) {
        List<Long> typeIds = new ArrayList<>();
        // 首先获取配置
        List<DeviceEnvTypeRespDTO> deviceEnvTypes = deviceEnvTypeApi.getByLandId(landId).getData();
        if(deviceEnvTypes != null) {
            typeIds.addAll(deviceEnvTypes.stream().map(DeviceEnvTypeRespDTO::getEnvTypeId).collect(Collectors.toList()));
        }
        return typeIds;
    }
}
