package cn.iocoder.yudao.module.pms.controller.admin.yanfan.cache;

import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.cache.domain.ModbusConfig;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.enums.ThingsModelType;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.redis.RedisCache;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.redis.RedisKeyBuilder;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.thingsmodel.vo.Datatype;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.thingsmodel.vo.IotYfThingsModelPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.thingsmodel.vo.PropertyDto;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.thingsmodel.vo.ThingsModelValueItem;
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.product.IotYfProductDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.things.IotYfThingsModelDO;
import cn.iocoder.yudao.module.pms.dal.mysql.yanfan.product.IotYfProductMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.yanfan.things.IotYfThingsModelMapper;
import cn.iocoder.yudao.module.pms.service.yanfan.thingsmodel.IotYfThingsModelService;
import cn.iocoder.yudao.module.supplier.dal.dataobject.product.ProductDO;
import cn.iocoder.yudao.module.supplier.dal.mysql.product.ProductMapper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.module.pms.controller.admin.yanfan.constant.Constants.EN_US;
import static cn.iocoder.yudao.module.pms.controller.admin.yanfan.constant.Constants.ZH_CN;


/**
 * 物模型缓存
 *
 * @author gsb
 * @date 2024/6/12 15:58
 */
@Service
public class TSLCacheImpl implements ITSLCache {

    @Resource
    private RedisCache redisCache;
    @Resource
    private IotYfProductMapper iotYfProductMapper;
    @Resource
    private IotYfThingsModelService thingsModelService;
//    @Resource
//    private IModbusConfigService modbusConfigService;
    @Autowired
    private IotYfThingsModelMapper iotYfThingsModelMapper;

    /**
     * 将物模型名称转换为对应语言
     *
     * @param item
     * @param language
     */
    private static void convertModelName(ThingsModelValueItem item, String language) {
        switch (language) {
            case EN_US:
                if (StringUtils.isNotEmpty(item.getName_en_US())) {
                    item.setName(item.getName_en_US());
                }
                break;
            case ZH_CN:
                if (StringUtils.isNotEmpty(item.getName_zh_CN())) {
                    item.setName(item.getName_zh_CN());
                }
                break;
        }
    }

    /**
     * 将物模型名称转换为对应语言
     *
     * @param item
     * @param language
     */
    private static void convertModelName(PropertyDto item, String language) {
        switch (language) {
            case EN_US:
                if (Objects.nonNull(item.getName_en_US())) {
                    item.setName(item.getName_en_US());
                }
                break;
            case ZH_CN:
                if (Objects.nonNull(item.getName_zh_CN())) {
                    item.setName(item.getName_zh_CN());
                }
                break;
        }
    }

    /**
     * 根据产品ID获取JSON物模型 -组装的方式是为了兼容前端数据结构
     *
     * @param productId
     * @return <p>
     * {
     * "functions": [
     * ],
     * "events": [
     * ],
     * "properties": [
     * {
     * "datatype": {
     * "max": 100,
     * "min": 1,
     * "step": 1,
     * "type": "integer",
     * "unit": "流明"
     * },
     * "id": "light",
     * "isChart": 1,
     * "isHistory": 1,
     * "isMonitor": 1,
     * "isReadonly": 1,
     * "name": "光强",
     * "order": 0,
     * "regId": "light",
     * "type": 1
     * }
     * ]
     * }
     * </p>
     */
    @Override
    public String getCacheThingsModelByProductId(Long productId) {
        assert !Objects.isNull(productId) : "产品id为空";
        // redis获取物模型
        Map<String, Object> map = redisCache.getCacheMap(RedisKeyBuilder.buildTSLCacheKey(productId));
        if (!CollectionUtils.isEmpty(map)) {
            //兼容原页面物模型的数据格式
            Map<String, List<PropertyDto>> listMap = map
                    .values()
                    .stream()
                    .map(v -> JSON.parseObject(v.toString(), PropertyDto.class))
                    .collect(Collectors.groupingBy(dto -> ThingsModelType.getName(dto.getType())));
            if (listMap != null) {
                for (List<PropertyDto> dtoList : listMap.values()) {
                    for (PropertyDto dto : dtoList) {
                        convertModelName(dto, "zh-CN");
                    }
                }
            }
            return JSON.toJSONString(listMap);
        }
        return setCacheThingsModelByProductId(productId);
    }

    /**
     * 缓存物模型 -返回JSON字符串
     *
     * @param productId
     * @return <p>
     * {\"functions\":[],\"events\":[],\"properties\":[{\"datatype\":{\"max\":100,\"min\":1
     * ,\"step\":1,\"type\":\"integer\",\"unit\":\"流明\"},
     * \"id\":\"light\",\"isChart\":1,\"isHistory\":1,\"isMonitor\":1,\"isReadonly\":1,
     * \"name\":\"光强\",\"order\":0,\"regId\":\"light\",\"type\":1}]}
     * </p>
     */
    public String setCacheThingsModelByProductId(Long productId) {
        Map<String, String> thingsModelMap = setThingModelAndModbusConfig(productId);
        /*组装成原格式数据*/
        Map<String, List<ThingsModelValueItem>> result = thingsModelMap
                .values()
                .stream()
                .map(x -> JSON.parseObject(x, ThingsModelValueItem.class))
                .collect(Collectors.groupingBy(dto -> ThingsModelType.getName(dto.getType())));
        if (result != null) {
            for (List<ThingsModelValueItem> itemList : result.values()) {
                for (ThingsModelValueItem item : itemList) {
                    convertModelName(item, "zh-CN");
                }
            }
        }
        String jsonString = JSON.toJSONString(result);
        IotYfProductDO product = new IotYfProductDO();
        product.setProductId(productId);
        IotYfProductDO iotYfProductDO = iotYfProductMapper.selectById(product);
        iotYfProductDO.setThingsModelsJson(jsonString);
        iotYfProductMapper.updateById(iotYfProductDO);
        return jsonString;
    }

    /**
     * 获取map物模型
     *
     * @param productId
     * @return <p>
     * 返回key-value
     * key: 物模型标识符
     * value：PropertyDto
     * </p>
     */
    public Map<String, ThingsModelValueItem> getCacheThMapByProductId(Long productId) {
        assert !Objects.isNull(productId) : "产品id为空";
        // redis获取物模型
        Map<String, Object> map = redisCache.getCacheMap(RedisKeyBuilder.buildTSLCacheKey(productId));
        if (!CollectionUtils.isEmpty(map)) {
            Map<String, ThingsModelValueItem> itemMap = map
                    .values()
                    .stream()
                    .map(v -> JSON.parseObject(v.toString(), ThingsModelValueItem.class))
                    .collect(Collectors.toMap(ThingsModelValueItem::getId, Function.identity()));
            for (ThingsModelValueItem item : itemMap.values()) {
                convertModelName(item, "zh-CN");
            }
            return itemMap;
        }
        return setCacheThMapByProductId(productId);
    }

    /**
     * 获取List集合物模型
     */
    @Override
    public List<ThingsModelValueItem> getThingsModelList(Long productId) {
        Map<String, ThingsModelValueItem> thingsModelMap = this.getCacheThMapByProductId(productId);
        if (thingsModelMap != null) {
            for (ThingsModelValueItem item : thingsModelMap.values()) {
                convertModelName(item, "zh-CN");
            }
        }
        return new ArrayList<>(thingsModelMap.values());
    }

    /**
     * 缓存物模型-返回Map
     *
     * @param productId <p>
     *                  返回key-value
     *                  key: 物模型标识符
     *                  value：PropertyDto
     *                  </p>
     */
    public Map<String, ThingsModelValueItem> setCacheThMapByProductId(Long productId) {
        Map<String, String> thingsModelMap = setThingModelAndModbusConfig(productId);
        Map<String, ThingsModelValueItem> itemMap = thingsModelMap
                .values()
                .stream()
                .map(value -> JSON.parseObject(value, ThingsModelValueItem.class))
                .collect(Collectors.toMap(ThingsModelValueItem::getId, Function.identity()));
        if (itemMap != null) {
            for (ThingsModelValueItem item : itemMap.values()) {
                convertModelName(item, "zh-CN");
            }
        }
        return itemMap;
    }

    /**
     * 获取单个物模型缓存值
     *
     * @param productId 产品id
     * @param identify  标识符
     * @return PropertyDto
     */
    @Override
    public ThingsModelValueItem getSingleThingModels(Long productId, String identify) {
        String cacheKey = RedisKeyBuilder.buildTSLCacheKey(productId);
        String value = redisCache.getCacheMapValue(cacheKey, identify);
        if (StringUtils.isEmpty(value)) {
            return null;
        }
        ThingsModelValueItem item = JSONObject.parseObject(value, ThingsModelValueItem.class);
        convertModelName(item, "zh-CN");
        return item;
    }

    /**
     * 整合物模型 & 整合modbus配置参数 & redis缓存
     *
     * @param productId
     */
    private Map<String, String> setThingModelAndModbusConfig(Long productId) {
        // 数据库查询物模型集合
//        IotYfThingsModelDO model = new IotYfThingsModelDO();
//        model.setProductId(productId);
//        model.setLimitValue("zh-CN");
        IotYfThingsModelPageReqVO pageReqVO = new IotYfThingsModelPageReqVO();
        pageReqVO.setProductId(productId);
        pageReqVO.setLimitValue("zh-CN");
        List<IotYfThingsModelDO> thingsModels = iotYfThingsModelMapper.selectList();
        //modbus配置参数整合到物模型
        ModbusConfig config = new ModbusConfig();
        config.setProductId(productId);
//        List<ModbusConfig> modbusConfigList = modbusConfigService.selectShortListByProductId(config);
//        if (!CollectionUtils.isEmpty(modbusConfigList)) {
//            Map<String, ModbusConfig> modbusMap = modbusConfigList
//                    .stream()
//                    .collect(Collectors.toMap(ModbusConfig::getIdentifier, Function.identity()));
//            for (IotYfThingsModelDO thingsModel : thingsModels) {
//                if (modbusMap.containsKey(thingsModel.getIdentifier())) {
//                    ModbusConfig modbusConfig = modbusMap.get(thingsModel.getIdentifier());
//                    thingsModel.setModbusConfig(modbusConfig);
//                }
//            }
//        }
        //List -> MAP
        Map<String, String> thingsModelMap = thingsModels
                .stream()
                .collect(Collectors.toMap(IotYfThingsModelDO::getIdentifier, thingsModel -> {
                    //转换数据，减少不必要数据
                    ThingsModelValueItem dto = new ThingsModelValueItem();
                    BeanUtils.copyProperties(thingsModel, dto);
                    dto
                            .setDatatype(JSONObject.parseObject(thingsModel.getSpecs(), Datatype.class))
                            .setId(thingsModel.getIdentifier())
                            .setName(thingsModel.getModelName())
//                            .setName_zh_CN(thingsModel.getModelName_zh_CN())
//                            .setName_en_US(thingsModel.getModelName_en_US())
                            .setOrder(thingsModel.getModelOrder())
                            .setModelId(thingsModel.getModelId())
                            //todo yf
//                            .setConfig(thingsModel.getModbusConfig())
                            .setTempSlaveId(thingsModel.getTempSlaveId());
                    return JSONObject.toJSONString(dto);
                }));

        /*缓存到redis*/
        String cacheKey = RedisKeyBuilder.buildTSLCacheKey(productId);
        //先删除缓存
        if (redisCache.containsKey(cacheKey)) {
            redisCache.deleteObject(cacheKey);
        }
        redisCache.hashPutAll(cacheKey, thingsModelMap);
        return thingsModelMap;
    }


    /**
     * 查询单个物模型
     *
     * @param model 物模型
     * @return 单个物模型
     */
    @Override
    @Cacheable(value = "thingsModel", key = "#root.methodName + '_' + #model.productId + '_' + #model.identifier + '_' + #model.tempSlaveId", unless = "#result == null")
    public IotYfThingsModelDO selectSingleThingsModel(IotYfThingsModelDO model) {
//        model.setLanguage("zh-CN");
        IotYfThingsModelPageReqVO pageReqVO = new IotYfThingsModelPageReqVO();
        pageReqVO.setLanguage("zh-CN");
        return iotYfThingsModelMapper.selectList(pageReqVO).get(0);
    }
}
