package org.bdware.sc.engine.hook;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.bdware.doip.codec.doipMessage.DoipMessage;
import org.bdware.doip.codec.doipMessage.DoipMessageFactory;
import org.bdware.doip.codec.doipMessage.DoipResponseCode;
import org.bdware.doip.codec.operations.BasicOperations;
import org.bdware.sc.JSEngine;
import org.bdware.sc.bean.ContractRequest;
import org.bdware.sc.entity.DoipMessagePacker;
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 java.nio.charset.StandardCharsets;

public class DOOPHandler implements AnnotationHook {
    public DOOPHandler() {

    }

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

    @Override
    public ArgPacks handle(JSEngine desktopEngine, ArgPacks argPacks) {
        Object arg = argPacks.arg;
        DoipMessagePacker doipMsgPackerArg = new DoipMessagePacker();

        if (arg instanceof DoipMessagePacker){
            doipMsgPackerArg = (DoipMessagePacker)arg;
        } else {
            // validate http request's params
            ContractRequest httpReq = argPacks.request;
            validateHTTPRequestArgs(httpReq);

            // set doipMsgPackerArg struct's params
            doipMsgPackerArg.setSource("http");
            doipMsgPackerArg.rawDoipMsg = convertContractRequestToDoipMessage(httpReq);
        }

        argPacks.arg = doipMsgPackerArg;
        return argPacks;
    }

    public static void validateHTTPRequestArgs(ContractRequest httpReq) {
        JsonElement httpArgs = httpReq.getArg();
        BasicOperations curOp = BasicOperations.getDoOp(httpReq.getAction());

        // get args rules and validate http args
        JsonElement httpArgsRules = getRulesForBasicOperation(curOp);
        ArgSchemaVisitor visitor = new ArgSchemaVisitor(httpArgs);
        visitor.visit(httpArgsRules);
    }

    public static JsonElement getRulesForBasicOperation(BasicOperations basicOperation) {

        switch(basicOperation) {
            case Hello:
                return JsonParser.parseString("{\"!doid\":\"string\"}");
            case Retrieve:
                return JsonParser.parseString("{\"!doid\":\"string\", \"!element\":\"boolean\"}");
            default:
                return null;
        }
    }

    public static DoipMessage convertContractRequestToDoipMessage(ContractRequest httpReq) {
        BasicOperations httpOperation = BasicOperations.getDoOp(httpReq.getAction());
        DoipMessage doipMessage = new DoipMessageFactory.DoipMessageBuilder().createRequest("", httpReq.getAction()).create();
        switch(httpOperation) {
            case Hello:
                doipMessage = new DoipMessageFactory.DoipMessageBuilder().createRequest(httpReq.getArg().getAsJsonObject().get("doid").getAsString(), httpReq.getAction()).create();
                break;
            case Retrieve:
                DoipMessageFactory.DoipMessageBuilder msgBuilder = new DoipMessageFactory.DoipMessageBuilder().createRequest(httpReq.getArg().getAsJsonObject().get("doid").getAsString(), httpReq.getAction());
                msgBuilder = msgBuilder.addAttributes("element", httpReq.getArg().getAsJsonObject().get("element").getAsString());
                doipMessage = msgBuilder.create();
                break;
        }

        return doipMessage;
    }

    public static DoipMessage convertJsonElementToDoipMessage(JsonElement jsonElementRet, DoipMessage msg) {
        DoipMessageFactory.DoipMessageBuilder builder = new DoipMessageFactory.DoipMessageBuilder();

        String responseCodeStr = jsonElementRet.getAsJsonObject().get("doipResponseCode").getAsString();
        DoipResponseCode responseCode = DoipResponseCode.UnKnownError;
        for (DoipResponseCode resp : DoipResponseCode.values()) {
            if (resp.toString().equals(responseCodeStr)) responseCode = resp;
        }

        DoipMessage doipRet = builder.createResponse(responseCode, msg).create();;
        doipRet.body.encodedData = jsonElementRet.getAsJsonObject().get("body").getAsJsonObject().get("encodedData").getAsString().getBytes(StandardCharsets.UTF_8);
        return doipRet;
    }
}
