package io.engagingspaces.graphql.schema;

import io.vertx.codegen.annotations.DataObject;
import io.vertx.core.eventbus.DeliveryOptions;
import io.vertx.core.json.JsonObject;

import java.util.Objects;

@DataObject
public class SchemaMetadata {

    /**
     * Key to the list of root query field names stored in schema metadata.
     */
    public static final String METADATA_QUERIES = "queries";

    /**
     * Key to the list of mutation field names stored in schema metadata.
     */
    public static final String METADATA_MUTATIONS = "mutations";

    private boolean async;
    private String schemaName;
    private String serviceAddress;
    private DeliveryOptions deliveryOptions;
    private JsonObject metadata;

    protected SchemaMetadata(JsonObject metadata, boolean async) {
        this.metadata = metadata;
        this.async = async;
    }

    public SchemaMetadata(JsonObject json) {
        Objects.requireNonNull(json, "Json metadata cannot be null");
        this.async = json.getBoolean("async");
        this.schemaName = json.getString("schemaName");
        if (json.containsKey("deliveryOptions")) {
            this.deliveryOptions = new DeliveryOptions(json.getJsonObject("deliveryOptions"));
        }
        this.metadata = json.copy();
        this.metadata.remove("async");
        this.metadata.remove("schemaName");
        this.metadata.remove("deliveryOptions");
    }

    public static SchemaMetadata create() {
        return new SchemaMetadata(new JsonObject(), false);
    }

    /**
     * Creates a new schema metadata instance.
     *
     * @param metadata   the additional custom metadata to pass to the service proxy
     * @return the schema metadata instance
     */
    public static SchemaMetadata create(JsonObject metadata) {
        return new SchemaMetadata(metadata, false);
    }

    public JsonObject toJson() {
        JsonObject result = metadata.copy()
                .put("async", async)
                .put("schemaName", schemaName);
        if (deliveryOptions != null) {
            result.put("deliveryOptions", new JsonObject()
                    .put("codecName", deliveryOptions.getCodecName())
                    .put("headers", deliveryOptions.getHeaders())
                    .put("sendTimeout", deliveryOptions.getSendTimeout()));
        }
        return result;
    }

    public boolean isAsync() {
        return async;
    }

    public SchemaMetadata setAsync(boolean async) {
        this.async = async;
        return this;
    }

    public String getSchemaName() {
        return schemaName;
    }

    public SchemaMetadata setSchemaName(String schemaName) {
        Objects.requireNonNull(schemaName, "Schema name cannot be null");
        this.schemaName = schemaName;
        return this;
    }

    public String getServiceAddress() {
        return serviceAddress;
    }

    public SchemaMetadata setServiceAddress(String address) {
        Objects.requireNonNull(address, "Service address cannot be null");
        this.serviceAddress = address;
        return this;
    }

    public DeliveryOptions getDeliveryOptions() {
        return deliveryOptions;
    }

    public SchemaMetadata setDeliveryOptions(DeliveryOptions deliveryOptions) {
        this.deliveryOptions = deliveryOptions;
        return this;
    }

    @SuppressWarnings("unchecked")
    public <T> T get(String key) {
        return (T) metadata.getValue(key);
    }

    public <T> SchemaMetadata put(String key, T value) {
        Objects.requireNonNull(key, "Metadata key cannot be null");
        Objects.requireNonNull(value, "Metadata value cannot be null");
        metadata.put(key, value);
        return this;
    }
}

@@ -554,35 +554,8 @@
 %22;%0A%0A
-    private boolean async;%0A
     
@@ -677,164 +677,65 @@
 ate 
-JsonObject metadata;%0A%0A    protected SchemaMetadata(JsonObject metadata, boolean async) %7B%0A        this.metadata = metadata;%0A        this.async = async;%0A    %7D
+boolean exposeToGateway;%0A    private JsonObject metadata;
 %0A%0A  
@@ -851,55 +851,8 @@
 %22);%0A
-        this.async = json.getBoolean(%22async%22);%0A
     
@@ -895,32 +895,163 @@
 (%22schemaName%22);%0A
+        this.serviceAddress = json.getString(%22serviceAddress%22);%0A        this.exposeToGateway = json.getBoolean(%22exposeToGateway%22);%0A
         if (json
@@ -1257,21 +1257,31 @@
 remove(%22
-async
+exposeToGateway
 %22);%0A    
@@ -1368,32 +1368,146 @@
 tions%22);%0A    %7D%0A%0A
+    /**%0A     * Creates a new schema metadata instance.%0A     *%0A     * @return the schema metadata instance%0A     */%0A
     public stati
@@ -1584,23 +1584,16 @@
 Object()
-, false
 );%0A    %7D
@@ -1639,32 +1639,82 @@
 etadata instance
+ initialized with the provided additional metadata
 .%0A     *%0A     * 
@@ -1952,15 +1952,8 @@
 data
-, false
 );%0A 
@@ -2061,21 +2061,31 @@
 ut(%22
-async%22, async
+schemaName%22, schemaName
 )%0A  
@@ -2105,38 +2105,103 @@
  .put(%22s
-chemaName%22, schemaName
+erviceAddress%22, serviceAddress)%0A                .put(%22exposeToGateway%22, exposeToGateway
 );%0A     
@@ -2568,15 +2568,23 @@
 ean 
-isAsync
+exposeToGateway
 () %7B
@@ -2599,21 +2599,31 @@
  return 
-async
+exposeToGateway
 ;%0A    %7D%0A
@@ -2656,13 +2656,23 @@
  set
-Async
+ExposeToGateway
 (boo
@@ -2676,21 +2676,22 @@
 boolean 
-async
+expose
 ) %7B%0A    
@@ -2703,21 +2703,32 @@
 his.
-async = async
+exposeToGateway = expose
 ;%0A  

Add flag for API gateway