package org.bdware.sc.contractexample;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bdware.irp.irpserver.IrpListenerInfo;
import org.bdware.irp.irpserver.IrpServerImpl;
import org.bdware.irp.irpserver.IrpServerInfo;
import org.bdware.sc.boundry.utils.SQLUtil;
import org.bdware.sc.engine.JSONTool;
import org.bdware.sc.util.JsonUtil;
import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class Resolver {
    static Logger LOGGER = LogManager.getLogger(Resolver.class);
    private IrsHandler testIrsHandler;

    public Resolver(ResolveConfig config) {
        this.config = config;
    }

    public static Resolver instance;

    public static Resolver main(ScriptObjectMirror obj) {

        if (Storage.instance == null) {

        }
        JsonObject jo = JSONTool.convertMirrorToJson(obj).getAsJsonObject();
        ResolveConfig config = JsonUtil.fromJson(jo.toString(), ResolveConfig.class);
        instance = new Resolver(config);
        instance.initAndStartServer();
        return instance;
    }

    public ResolveConfig config;

    public static JsonObject resolve(String name) {
        try {
            name = instance.testIrsHandler.fixScheme(name);
            String[] schemeAndID = name.split("://");
            System.out.println("[GDResolver] " + name + " --> " + schemeAndID.length);
            if (!schemeAndID[0].equals(instance.config.scheme)) {
                JsonObject ret = new JsonObject();
                ret.addProperty("msg", "unknown scheme, need delegate!");
                ret.addProperty("doid", name);
                ret.addProperty("code", 1);
                return ret;
            } else {
                if (schemeAndID[1].startsWith(instance.config.prefix + "/")) {
                    String appName = schemeAndID[1].split("/")[1];
                    JsonObject resolveResult = instance.testIrsHandler.resolveInternal(appName);
                    if (resolveResult == null) {
                        resolveResult = new JsonObject();
                        resolveResult.addProperty("code", 2);
                        resolveResult.addProperty("msg", "can't resolve:" + appName);
                        return resolveResult;
                    }
                    if (resolveResult != null && resolveResult.has("contractName")) {
                        String contractName = resolveResult.get("contractName").getAsString();
                        String key = resolveResult.get("sm2keypair").getAsString();
                        String publicKey = JsonParser.parseString(key).getAsJsonObject().get("publicKey").getAsString();
                        File findDir = findDir(contractName, publicKey);
                        File sqlConf = new File(findDir, "sql.conf");
                        if (sqlConf.exists()) {
                            JsonElement jo = JsonParser.parseReader(new FileReader(sqlConf));
                            resolveResult.add("dbInfo", jo);

                        }
                    }

                    resolveResult.addProperty("code", 0);
                    return resolveResult;
                } else {
                    JsonObject ret = new JsonObject();
                    ret.addProperty("msg", "unknown prefix, need delegate!");
                    ret.addProperty("doid", name);
                    ret.addProperty("code", 1);
                    return ret;
                }
            }
        } catch (Exception e) {
            JsonObject ret = new JsonObject();
            ret.addProperty("msg", new String(IrsHandler.fromException(e)));
            ret.addProperty("doid", name);
            ret.addProperty("code", 1);
            return ret;
        }
    }

    private static File findDir(String contractName, String publicKey) {
        File f = new File("/bdcontract/BDWareProjectDir/private");
        if (f.exists()) {
            File dir = new File(f, publicKey);
            if (dir.exists()) {
                dir = new File(dir, contractName);
                return dir;
            }
        }
        return null;
    }

    public static ResolveConfig getConfig() {
        return instance.config;
    }


    public static String peekDB(ScriptObjectMirror obj) {
        try {
            JsonObject jo = JSONTool.convertMirrorToJson(obj).getAsJsonObject();
            Connection conn = SQLUtil.getConnection(instance.config.dbUrl, instance.config.dbUserName, instance.config.dbPwd);
            Statement stmt = conn.createStatement();
            ResultSet result = stmt.executeQuery("select * from app ;");
            ResultSetMetaData meta = result.getMetaData();
            JsonArray array = new JsonArray();
            for (; result.next(); ) {
                JsonObject ele = new JsonObject();
                array.add(ele);
                for (int j = 1; j <= meta.getColumnCount(); j++) {
                    int type = meta.getColumnType(j);
                    switch (type) {
                        case -6:
                        case 5:
                        case 4:
                            ele.addProperty(meta.getColumnName(j), result.getInt(j));
                            break;
                        case -5:
                            ele.addProperty(meta.getColumnName(j), result.getLong(j));
                            break;
                        case 6:
                        case 7:
                        case 8:
                            ele.addProperty(meta.getColumnName(j), result.getDouble(j));
                            break;
                        default:
                            ele.addProperty(meta.getColumnName(j), result.getString(j));
                            break;

                    }
                }
            }
            return array.toString();
        } catch (Exception e) {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(bo));
            return new String(bo.toByteArray());
        }

    }

    public void initAndStartServer() {
        //init irpserver
        IrpListenerInfo listenerInfo = new IrpListenerInfo(config.ip, config.port, "TCP");
        List<IrpListenerInfo> listenerInfos = new ArrayList<>();
        listenerInfos.add(listenerInfo);
        IrpServerInfo info = new IrpServerInfo("bdware", "no description", listenerInfos);
        IrpServerImpl server = new IrpServerImpl(info);
        testIrsHandler = new IrsHandler(this);

        server.setIrpServerHandler(testIrsHandler);
        server.start();
    }
}
