/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.seatunnel.datasource.plugin.kepserver;

import org.apache.seatunnel.api.configuration.util.OptionRule;
import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginException;
import org.apache.seatunnel.datasource.plugin.api.model.TableField;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;


import org.eclipse.milo.opcua.stack.core.NamespaceTable;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort;

import com.alibaba.fastjson2.JSONObject;


import java.math.BigDecimal;
import java.util.*;


public class KepServerDataSourceChannel implements DataSourceChannel {

    private static final String DATABASE = "default";

    public static class Holder {
        private static final KepServerDataSourceChannel INSTANCE = new KepServerDataSourceChannel();
    }

    public static KepServerDataSourceChannel getInstance() {
        return Holder.INSTANCE;
    }

    @Override
    public OptionRule getDataSourceOptions(String pluginName) {
        return KepServerOptionRule.optionRule();
    }

    @Override
    public OptionRule getDatasourceMetadataFieldsByDataSourceName(String pluginName) {
        return KepServerOptionRule.metadataRule();
    }

    @Override
    public List<String> getTables(
            String pluginName,
            Map<String, String> requestParams,
            String database,
            Map<String, String> option) {
        //  checkArgument(StringUtils.equalsIgnoreCase(database, DATABASE), "database must be
        // default");
        try {
            if (requestParams.isEmpty()) {
                return new ArrayList<>();
            }
            ReadKepServer example = new ReadKepServer(requestParams);

            Map map = new KepServerClientRunner(example, true).run();


            if (map!=null && map.size()>0) {
                String ns = requestParams.get("ns") + "";
                String id = requestParams.get("id") + "";
                NodeId nodeId = new NodeId(UShort.valueOf(ns), id);
                return Arrays.asList(nodeId.toString());
            }
            return new ArrayList<>();
        } catch (Exception ex) {
            throw new DataSourcePluginException(
                    "check kafka connectivity failed, " + ex.getMessage(), ex);
        }
    }

    @Override
    public List<String> getDatabases(
            String pluginName, Map<String, String> requestParams) {
        String suffix = requestParams.get("suffix");
        if (StringUtils.isNotEmpty(suffix)) {
            return Arrays.asList(suffix);
        }

        return DEFAULT_DATABASES;
    }

    @Override
    public boolean checkDataSourceConnectivity(
            String pluginName, Map<String, String> requestParams) {
        try {
            ReadKepServer example = new ReadKepServer(requestParams);
            new KepServerClientRunner(example, true);
            return true;
        } catch (Exception ex) {
            throw new DataSourcePluginException(
                    "check kafka connectivity failed, " + ex.getMessage(), ex);
        }
    }

    @Override
    public List<TableField> getTableFields(
            String pluginName,
            Map<String, String> requestParams,
            String database,
            String table) {
        // checkArgument(StringUtils.equalsIgnoreCase(database, DATABASE), "database must be
        // default");
        // checkArgument(StringUtils.equalsIgnoreCase(database, DATABASE), "database must be
        // default");
        try {
            List<TableField> tableFields = new ArrayList<>();
            ReadKepServer example = new ReadKepServer(requestParams);

            Map<String,Object> map = new KepServerClientRunner(example, true).run();
            for(Map.Entry<String,Object> m:map.entrySet()) {
                TableField tableField = new TableField();
                tableField.setName(m.getKey());
                tableField.setNullable(true);
                if(m.getValue() instanceof  Integer){
                    tableField.setType("int");
                } else if(m.getValue() instanceof BigDecimal){
                    tableField.setType("double");
                } else if (m.getValue() instanceof  Date){
                    tableField.setType("date");
                } else  if(m.getValue() instanceof Short){
                    tableField.setType("short");
                } else {
                    tableField.setType("varchar");
                }
                tableFields.add(tableField);
            }
           return tableFields;
        } catch (Exception ex) {
            throw new DataSourcePluginException(
                    "check mqtt getTableFields failed, " + ex.getMessage(), ex);
        }
    }

    @Override
    public Map<String, List<TableField>> getTableFields(
            String pluginName,
            Map<String, String> requestParams,
            String database,
            List<String> tables) {
        // checkArgument(StringUtils.equalsIgnoreCase(database, DATABASE), "database must be
        // default");
        Map<String, List<TableField>> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(tables)) {
            for (String table : tables) {
                map.put(table, getTableFields(pluginName, requestParams, database, table));
            }
        }

        return map;
    }


}
