package com.zd.laboratory.utils;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.zd.common.core.annotation.DeviceID;
import com.zd.common.core.annotation.FunctionMapper;
import com.zd.common.core.annotation.NewFunctionMapper;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.Assert;
import com.zd.common.core.utils.reflect.ReflectUtils;
import com.zd.laboratory.config.HardwareFunctionStatusConfig;
import com.zd.laboratory.domain.SensorConfig;
import com.zd.laboratory.service.ILabSensorService;
import com.zd.laboratory.service.impl.LabSubjectManagerService;
import com.zd.laboratory.socket.vo.TransmissionVo;
import com.zd.system.api.laboratory.domain.SensorFunctionStatus;
import com.zd.system.api.laboratory.domain.vo.SubFunction;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 测点映射处理帮助类
 * @Author: zhoupan
 * @Date: 2021/10/06/8:54
 * @Description:
 */
@Component
public class FunctionMapperUtil {

    @Autowired
    HardwareFunctionStatusConfig hardwareFunctionStatusConfig;
    @Autowired
    ILabSensorService labSensorService;


    Logger logger = LoggerFactory.getLogger(FunctionMapperUtil.class);

    /**
     * 缓存数据：设备ID
     */
    private Map<Class,Field> cacheMap = new ConcurrentHashMap<>();

    /**
     * 缓存注解数据不用每次解析
     */
    private Map<Class, Map<Field,FunctionMapper>> cacheFunctionMapperMap = new ConcurrentHashMap<>();


    private Map<String,String> map = new HashMap<>();
    @PostConstruct
    public void initFunNum()
    {
        Field[] fields =ReflectUtil.getFields(SensorConfig.class);
        Arrays.stream(Optional.ofNullable(fields)
                        .orElseThrow(()->new ServiceException("未配置测点关联关系")))
                                .forEach(a->{
                                    NewFunctionMapper annotation = a.getAnnotation(NewFunctionMapper.class);
                                    if(annotation!=null)
                                    {
                                        String value = annotation.value();
                                        if(map.containsKey(value))
                                        {
                                            throw new ServiceException(StrUtil.format("配置错误，存在重复配置value：{}，属性：{}",value,a.getName()));
                                        }
                                        map.put(annotation.value(),a.getName());
                                    }
                                });
    }

    /**
     * 将功能测点和实验室数据进行组装
     * 2021年10月28日 ：已启用，当前从配置中获取网关个路与传感器功能对应关系
     * 不再使用
     * 请参考 {@link FunctionMapperUtil#mapper(TransmissionVo, SensorConfig)}
     * @param o
     * @return
     * @throws InterruptedException
     */
    @Deprecated
    public SubFunction mapperSubFunction(Object o)  {
        List<SensorFunctionStatus> mapper = mapper(o);
        SubFunction  subFunction= new SubFunction();
        subFunction.setFunctionStatuses(mapper);
        String s = Optional.ofNullable(mapper)
                .filter(a -> a.size() > 0)
                .map(a -> a.get(0).getHardwareNum())
                .orElse(null);
        //通过缓存获取数据
        Long cacheSubByGateway  = labSensorService.getCacheSubByGateway(s);
        return subFunction.setSubId(cacheSubByGateway);

    }

    /**
     * 把设备发送的数据 映射为功能测点数据
     * 现在采用双向绑定：必须配置的测点功能才能映射，以后可以考虑改为单项，好处是少一个配置，坏处少了参考，容易出错，且不易发现
     * @param o
     * @return
     */
    public List<SensorFunctionStatus> mapper(Object o)
    {
        if(o==null) return Collections.emptyList();
        //暂时先把缓存去掉，情况有变 ！！
        Map<Class, Map<Field,FunctionMapper>>  tempCacheFunctionMapperMap = new HashMap<>();

        if(!tempCacheFunctionMapperMap.containsKey(o.getClass()))
        {
            //获取对象的属性
            Field[] fields = ReflectUtil.getFields(o.getClass());
            AtomicReference<DeviceID> annotation= new AtomicReference<>();
            Map<Field,FunctionMapper> tempMap = new HashMap<>();
            Stream.of(fields).forEach(a -> {
                        //获取注解
                        FunctionMapper functionMapper = a.getAnnotation(FunctionMapper.class);
                        DeviceID annotation1 = a.getAnnotation(DeviceID.class);
                        logger.debug("属性：{},注解{}",a.getName(),annotation1==null);
                        //这样只会拿第一个循环到的
                        annotation.compareAndSet(null,annotation1);
//                        if(annotation.get()!=null&&!cacheMap.containsKey(o.getClass()))
//                        {
//                            cacheMap.put(o.getClass(),a);
//                        }
                        Optional<FunctionMapper> functionMapper1 = Optional.ofNullable(functionMapper)
                                .filter(b -> StrUtil.isNotEmpty(b.funNum()));
                        if(functionMapper1.isPresent())
                        {
                            tempMap.put(a,functionMapper);
                        }

                    }
                    );
            Assert.isNotNull(annotation.get(),StrUtil.format("{} class ，没有找到设备ID映射配置！"));
            if(!tempCacheFunctionMapperMap.containsKey(o.getClass()))
            {
                tempCacheFunctionMapperMap.put(o.getClass(),tempMap);
            }
        }
        Field field = cacheMap.get(o.getClass());
        String num  = String.valueOf(ReflectUtil.getFieldValue(o, field));
        return Optional.ofNullable(tempCacheFunctionMapperMap.get(o.getClass()))
                .orElseGet(Collections::emptyMap)
                .entrySet()
                .stream()
                .filter(a->a.getKey()!=null)
                .map(a->{
                    Field key = a.getKey();
                    FunctionMapper value = a.getValue();
                    SensorFunctionStatus functionStatus = hardwareFunctionStatusConfig.getMapFunNum().get(value.funNum());
                    if(functionStatus==null) return null;
                    SensorFunctionStatus newFunctionStatus = new SensorFunctionStatus();
                    BeanUtils.copyProperties(functionStatus,newFunctionStatus);
                    Object fieldValue = ReflectUtil.getFieldValue(o, key);
                    String s = String.valueOf(fieldValue);
                    //设置ID
                    {
                        newFunctionStatus.setHardwareNum(num);
                    }
                    //切割数据
                    if(value.isUnit())
                    {
                        if(StrUtil.isNotEmpty(s))
                        {
                            //不要报错！
                            String[] split = s.split(value.unitSpit());
                            if(split!=null)
                            {
                                newFunctionStatus.setVal(split[0]);
                                if(split.length>1)
                                {
                                    newFunctionStatus.setUnit(split[1]);
                                }
                            }
                        }
                    }
                    else
                    {
                        newFunctionStatus.setVal(s);
                        newFunctionStatus.setUnit(value.unit());

                    }
                    return newFunctionStatus;

                })
                .filter(a->a!=null)
                .sorted((c,d)-> NumberUtil.compare(c.getOrder(),d.getOrder()))
                .collect(Collectors.toList());
    }

    /**
     * 实现了根据配置的动态路由匹配 解决多路问题
     * @param transmissionVo
     * @param sensorConfig
     * @return
     */
    public  SubFunction mapper(TransmissionVo transmissionVo,SensorConfig sensorConfig)
    {
        if(sensorConfig==null) return null;
        //根据配置解析
        List<SensorFunctionStatus> mapper = confiSensorData(transmissionVo, sensorConfig);

        SubFunction  subFunction= new SubFunction();
        subFunction.setFunctionStatuses(mapper);
//        String s = Optional.ofNullable(mapper)
//                .filter(a -> a.size() > 0)
//                .map(a -> a.get(0).getHardwareNum())
//                .orElse(null);
        //通过缓存获取数据
        Long  cacheSubByGateway = labSensorService.getCacheSubByGateway(transmissionVo.getA3());
        return subFunction.setSubId(cacheSubByGateway);
    }
    //todo 先写死有时间优化下
    public List<SensorFunctionStatus> confiSensorData(TransmissionVo transmissionVo, SensorConfig sensorConfig) {
        List<SensorFunctionStatus> collect = map.entrySet()
                .stream()
                .map(a ->{
                    Object o = ReflectUtils.invokeGetter(sensorConfig, a.getValue());
                    if(o!=null)
                    {
                        List<SensorFunctionStatus> list = doConfig(transmissionVo, String.valueOf(o), a.getKey());
                        return list;
                    }else
                    {
                        return null;
                    }
                })
                .filter(a->a!=null)
                .flatMap(List::stream)
                .sorted((c,d)-> NumberUtil.compare(c.getOrder(),d.getOrder()))
                .collect(Collectors.toList());
        return collect;
    }

    private List<SensorFunctionStatus> doConfig(TransmissionVo transmissionVo, String data, String type) {
        if(data==null) return Collections.emptyList();
        SensorFunctionStatus functionStatus = hardwareFunctionStatusConfig.getMapFunNum().get(type);
        if(functionStatus==null) return Collections.emptyList();
        String[] nums = data.split(",");
        if(nums==null||nums.length==0) return Collections.emptyList();
        List<SensorFunctionStatus> list= new ArrayList<>(nums.length);
        for (String num : nums) {
            if(StrUtil.isBlank(num))continue;
            String field = "A7_" + num;
            Object o = ReflectUtils.invokeGetter(transmissionVo, field);
            SensorFunctionStatus newFunctionStatus = new SensorFunctionStatus();
            BeanUtils.copyProperties(functionStatus,newFunctionStatus);
            list.add(newFunctionStatus);
            String s = String.valueOf(o);
            newFunctionStatus.setRouteNum(Integer.parseInt(num));
            //切割数据
            newFunctionStatus.setVal(s);
            //todo 单位改为手动给
            }
        return list;
    }
}
