package org.bdware.sc.engine.hook;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bdware.sc.JSEngine;
import org.bdware.sc.bean.ContractRequest;
import org.bdware.sc.boundry.ScriptReturnException;
import org.bdware.sc.engine.DesktopEngine;
import org.bdware.sc.engine.JSONTool;
import org.bdware.sc.node.AnnotationHook;
import org.bdware.sc.node.AnnotationNode;
import org.bdware.sc.node.ArgPacks;
import org.bdware.sc.node.FunctionNode;
import wrp.jdk.nashorn.internal.objects.Global;
import wrp.jdk.nashorn.internal.runtime.Context;
import wrp.jdk.nashorn.internal.runtime.PropertyMap;
import wrp.jdk.nashorn.internal.scripts.JO;

@YJSAnnotation(name = "Access")
public class AccessHandler implements AnnotationHook {
    public String acFunction;
    public boolean requireSign;

    public AccessHandler(AnnotationNode annoNode) {
        requireSign = false;
        String content = annoNode.getArgs().get(0);
        JsonElement je = JsonParser.parseString(content);
        if (je.isJsonPrimitive() && je.getAsJsonPrimitive().getAsString().equals("verified")) {
            requireSign = true;
        }
        if (je.isJsonObject()) {
            acFunction = je.getAsJsonObject().get("ACFunction").getAsString();
        }
    }

    public static AccessHandler fromAnnotationNode(FunctionNode funNode, AnnotationNode annoNode) {
        return new AccessHandler(annoNode);
    }

    @Override
    public ArgPacks handle(JSEngine desktopEngine, ArgPacks argPacks) {
        if (requireSign) {
            if (!argPacks.request.verifySignature()) {
                throw new ScriptReturnException(JsonParser.parseString("{\"code\":400,\"msg\":\"permission denied\"}"));
            }
            return argPacks;
        }
        if (acFunction == null) return argPacks;
        DesktopEngine de = (DesktopEngine) desktopEngine;
        Global oldGlobal = Context.getGlobal();
        Global newGlobal = de.getDesktopGlobal();
        boolean globalChanged = (oldGlobal != newGlobal);
        try {
            if (globalChanged) {
                Context.setGlobal(newGlobal);
            }
            ContractRequest input = argPacks.request;
            JO jo = new JO(PropertyMap.newMap());
            jo.put("requester", input.getRequester(), false);
            jo.put("action", input.getAction(), false);
            jo.put("arg", JSONTool.convertJsonElementToMirror(input.getArg()), false);
            de.engine.invokeFunction(acFunction, jo);
            return argPacks;
        } catch (ScriptReturnException e) {
            throw e;
        } catch (Exception e) {
            JsonObject jo = new JsonObject();
            jo.addProperty("code", "401");
            jo.addProperty("msg", "access check meets exception! " + e);
            throw new ScriptReturnException(jo);
        } finally {
            if (globalChanged) Context.setGlobal(oldGlobal);

        }

    }
}
