package com.openshift.jenkins.plugins.pipeline.model;

import hudson.model.TaskListener;

import java.util.List;
import java.util.Map;

import net.sf.json.JSONObject;

import org.jboss.dmr.ModelNode;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;

import com.openshift.jenkins.plugins.pipeline.MessageConstants;
import com.openshift.jenkins.plugins.pipeline.OpenShiftApiObjHandler;
import com.openshift.restclient.IClient;
import com.openshift.restclient.model.IResource;

public interface IOpenShiftApiObjHandler extends IOpenShiftPlugin {

    default String fetchApiJsonFromApiServer(boolean chatty,
            TaskListener listener, Map<String, String> overrides,
            String apiDomain) {
        String json = null;
        try {
        	json = httpGet(chatty, listener, overrides, this.getApiURL(overrides)
                + "/swaggerapi" + apiDomain + "/v1");
        } catch (Throwable t) {
        	if (chatty) {
        		listener.getLogger().println(t.getMessage());
        	}
        	json = httpGet(chatty, listener, overrides, this.getApiURL(overrides)
        			+ "/apis");
        }
        return json;
    }

    default void importJsonOfApiTypes(boolean chatty, TaskListener listener,
            Map<String, String> overrides, String apiDomain, String json) {
        if (json == null)
            return;
        ModelNode oapis = ModelNode.fromJSONString(json);
        if (oapis.has("apis")) {
            // older path
            ModelNode apis = oapis.get("apis");
            List<ModelNode> apiList = apis.asList();
            for (ModelNode api : apiList) {
                String path = api.get("path").asString();
                ModelNode operations = api.get("operations");
                List<ModelNode> operationList = operations.asList();
                for (ModelNode operation : operationList) {
                    String type = operation.get("type").asString();
                    String method = operation.get("method").asString();
                    if (type.startsWith("v1.") && method.equalsIgnoreCase("POST")) {
                        String coreType = type.substring(3);
                        if (!OpenShiftApiObjHandler.apiMap.containsKey(coreType)) {
                            String typeStrForURL = null;
                            String[] pathPieces = path.split("/");
                            for (String pathPiece : pathPieces) {
                                if (pathPiece.equalsIgnoreCase(coreType + "s")
                                        || pathPiece.equalsIgnoreCase(coreType)) {
                                    typeStrForURL = pathPiece;
                                    break;
                                }
                            }
                            if (typeStrForURL != null) {
                                if (chatty)
                                    listener.getLogger().println(
                                            "\nOpenShiftCreator: adding from API server swagger endpoint new type "
                                                    + coreType + " with url str "
                                                    + typeStrForURL + " to domain "
                                                    + apiDomain);
                                OpenShiftApiObjHandler.apiMap.put(coreType,
                                        new String[] { apiDomain, typeStrForURL });
                            }
                        }
                    }
                }
                
            }
        }

        if (oapis.has("groups")) {
            // new path
            ModelNode groups = oapis.get("groups");
            List<ModelNode> groupList = groups.asList();
            for (ModelNode group : groupList) {
            	String name = group.get("name").asString();
            	String groupjson = null;
            	try {
            		groupjson = httpGet(chatty, listener, overrides, this.getApiURL(overrides) + "/apis/" + name + "/v1");
            	} catch (Throwable t) {
            		if (chatty)
            			listener.getLogger().println(t.getMessage());
            	}
            	if (groupjson == null)
            		continue;
            	ModelNode groupjsonNode = ModelNode.fromJSONString(groupjson);
            	ModelNode resources = groupjsonNode.get("resources");
            	List<ModelNode> resourceList = resources.asList();
            	for (ModelNode resource : resourceList) {
            		String kind = resource.get("kind").asString();
            		if (!OpenShiftApiObjHandler.apiMap.containsKey(kind)) {
                        if (chatty)
                            listener.getLogger().println(
                                    "\nOpenShiftCreator: adding from API server swagger endpoint new type "
                                            + kind + " is openshift " + name.contains("openshift"));
                        String value = kind.toLowerCase();
                        if (!value.endsWith("s"))
                        	value = value + "s";
                		if (name.contains("openshift")) {
                			OpenShiftApiObjHandler.apiMap.put(kind, new String[] {OpenShiftApiObjHandler.oapi, kind.toLowerCase()});
                		} else {
                			OpenShiftApiObjHandler.apiMap.put(kind, new String[] {OpenShiftApiObjHandler.api, kind.toLowerCase()});
                		}            			
            		}
            	}
            }
        }
    }

    // TODO openshift-restclient-java's IApiTypeMapper is not really accessible
    // from our perspective,
    // without accessing/recreating the underlying OkHttpClient, so until that
    // changes, we use our own
    // type mapping
    default void updateApiTypes(boolean chatty, TaskListener listener,
            Map<String, String> overrides) {
        importJsonOfApiTypes(
                chatty,
                listener,
                overrides,
                OpenShiftApiObjHandler.oapi,
                fetchApiJsonFromApiServer(chatty, listener, overrides,
                        OpenShiftApiObjHandler.oapi));
        importJsonOfApiTypes(
                chatty,
                listener,
                overrides,
                OpenShiftApiObjHandler.api,
                fetchApiJsonFromApiServer(chatty, listener, overrides,
                        OpenShiftApiObjHandler.api));
    }

    default ModelNode hydrateJsonYaml(String jsonyaml, TaskListener listener) {
        // construct json/yaml node
        ModelNode resources = null;
        try {
            resources = ModelNode.fromJSONString(jsonyaml);
        } catch (Exception e) {
            Yaml yaml = new Yaml(new SafeConstructor());
            Map<String, Object> map = (Map<String, Object>) yaml.load(jsonyaml);
            JSONObject jsonObj = JSONObject.fromObject(map);
            try {
                resources = ModelNode.fromJSONString(jsonObj.toString());
            } catch (Throwable t) {
                if (listener != null)
                    t.printStackTrace(listener.getLogger());
            }
        }
        return resources;
    }

    default int[] deleteAPIObjs(IClient client, TaskListener listener,
            String namespace, String type, String key,
            List<Map<String, String>> listOfLabels, boolean chatty) {
        int[] ret = new int[2];
        int deleted = 0;
        int failed = 0;

        if (chatty)
            listener.getLogger()
                    .println(
                            String.format(
                                    "deleteAPIObjs with namespace %s type %s key %s labels %s",
                                    namespace, type, key, listOfLabels));
        if (type != null && key != null) {
            IResource resource = client.get(type, key, namespace);
            if (resource != null) {
                client.delete(resource);
                listener.getLogger().println(
                        String.format(MessageConstants.DELETED_OBJ, type, key));
                deleted++;
            } else {
                listener.getLogger().println(
                        String.format(MessageConstants.FAILED_DELETE_OBJ, type,
                                key));
                failed++;
            }
        }

        if (listOfLabels != null && listOfLabels.size() > 0) {
            for (Map<String, String> labels : listOfLabels) {
                if (chatty)
                    listener.getLogger()
                            .println(
                                    String.format(
                                            "deleteAPIObjs calling list with type %s namespace %s labels %s",
                                            type, namespace, labels));
                List<IResource> resources = client
                        .list(type, namespace, labels);
                for (IResource resource : resources) {
                    if (resource != null) {
                        if (chatty)
                            listener.getLogger().println(
                                    "deleteAPIObjs calling delete on "
                                            + resource.toJson(false));
                        client.delete(resource);
                        listener.getLogger().println(
                                String.format(MessageConstants.DELETED_OBJ,
                                        type, resource.getName()));
                        deleted++;
                    }
                }
            }
        }

        ret[0] = deleted;
        ret[1] = failed;
        return ret;
    }
}