package com.iailab.module.data.channel.kio.collector;

import com.iailab.module.data.channel.kio.entity.ChannelKioDeviceEntity;
import com.iailab.module.data.channel.kio.service.ChannelKioDeviceService;
import com.iailab.module.data.channel.opcua.collector.OpcUaUtils;
import com.iailab.module.data.common.enums.CommonConstant;
import com.iailab.module.data.common.enums.DataSourceType;
import com.iailab.module.data.common.utils.TagUtils;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author PanZhibao
 * @Description
 * @createTime 2024年06月04日
 */
@Slf4j
@Component
public class KingIOCollector {

    @Resource
    private ChannelKioDeviceService channelKioDeviceService;

    private Map<String, KingIOClient> clientMap = new ConcurrentHashMap<>();

    private Map<String, ChannelKioDeviceEntity> deviceMap = new HashMap<>();

    public synchronized KingIOClient getClient(String sourceId) throws Exception {
        if (!clientMap.containsKey(sourceId)) {
            ChannelKioDeviceEntity deviceEntity = channelKioDeviceService.info(sourceId);
            deviceMap.put(sourceId, deviceEntity);
            KingIOClient kingIOClient = new KingIOClient(deviceEntity.getInstanceName());
            clientMap.put(sourceId, kingIOClient);
            if (!kingIOClient.login(deviceEntity.getAddress(), deviceEntity.getPort(), deviceEntity.getUsername(), deviceEntity.getPassword())) {
                throw new Exception("登录异常");
            }
        }
        KingIOClient kingIOClient = clientMap.get(sourceId);
        if (!kingIOClient.isConnect()) {
            kingIOClient.reLogin();
        }
        return kingIOClient;
    }

    public String getTagValue(String sourceId, String tagName) {
        String value = CommonConstant.BAD_VALUE.toString();
        try{
            KingIOClient client = this.getClient(sourceId);
            value = client.getTagValue(tagName);
        }catch (Exception ex){
            ex.printStackTrace();
            return value;
        }
        return value;
    }

    public void setTagValue(String sourceId, String tagName, String newValue, String dataType) throws Exception {
        try {
            KingIOClient client = this.getClient(sourceId);
            switch (dataType) {
                case "float":
                    log.debug("Float,tagName=" + tagName + ",Value=" + Float.parseFloat(newValue));
                    client.writeFloatValue(tagName, Float.parseFloat(newValue));
                    break;
                case "int":
                    log.debug("Int,tagName=" + tagName + ",Value=" + new BigDecimal(newValue).intValue());
                    client.writeIntValue(tagName, new BigDecimal(newValue).intValue());
                    break;
                case "boolean":
                    log.debug("Boolean,tagName=" + tagName + ",Value=" + newValue);
                    client.writeBooleanValue(tagName, Boolean.parseBoolean(newValue));
                    break;
                default:
                    log.warn("##################### No DataType ####################");
                    break;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        }
    }

    public Map<String, Object> getTagValues(List<String[]> params) {
        if (CollectionUtils.isEmpty(params)) {
            return new HashMap<>();
        }
        Map<String, Object> result = new HashMap<>(params.size());

        /*params.forEach(item -> {
            try {
                KingIOClient client = this.getClient(item[0]);
                String value = client.getTagValue(item[1]);
                result.put(TagUtils.genTagId(DataSourceType.KIO.getCode(), deviceMap.get(item[0]).getInstanceName(), item[1]), value);
            } catch (Exception ex) {
                ex.printStackTrace();
                result.put(TagUtils.genTagId(DataSourceType.KIO.getCode(), deviceMap.get(item[0]).getInstanceName(), item[1]), CommonConstant.BAD_VALUE);
            }
        });*/

        Map<String, List<String[]>> sourceGroup = new HashMap<>();
        params.forEach(item -> {
            if (sourceGroup.containsKey(item[0])) {
                sourceGroup.get(item[0]).add(item);
            } else {
                List<String[]> list = new ArrayList<>();
                list.add(item);
                sourceGroup.put(item[0], list);
            }
        });
        sourceGroup.forEach((k, v) -> {
            try {
                KingIOClient client = this.getClient(k);
                List<String> tagNames = v.stream().map(t -> {
                    return t[1];
                }).collect(Collectors.toList());
                Map<String, String> tagsValue = client.getTagsValue(tagNames);
                for (Map.Entry<String, String> tagValue : tagsValue.entrySet()) {
                    result.put(TagUtils.genTagId(DataSourceType.KIO.getCode(), deviceMap.get(k).getInstanceName(), tagValue.getKey()), tagValue.getValue());
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        });
        return result;
    }
}