package cz.creeper.customitemlibrary.feature.inventory.simple;

import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import cz.creeper.customitemlibrary.CustomItemLibrary;
import cz.creeper.customitemlibrary.feature.CustomFeatureRegistry;
import cz.creeper.customitemlibrary.feature.DurabilityRegistry;
import lombok.AccessLevel;
import lombok.Getter;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.imageio.ImageIO;

public class SimpleCustomInventoryRegistry implements CustomFeatureRegistry<SimpleCustomInventory, SimpleCustomInventoryDefinition> {
    public static final String MODEL_DIRECTORY_NAME = "gui";
    private static final SimpleCustomInventoryRegistry INSTANCE = new SimpleCustomInventoryRegistry();

    @Getter(value = AccessLevel.PRIVATE, lazy = true)
    private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
    private final Set<SimpleCustomInventoryDefinition> definitions = Sets.newHashSet();

    @Override
    public void register(SimpleCustomInventoryDefinition definition) {
        Preconditions.checkNotNull(definition, "definition");
        Preconditions.checkArgument(!definitions.contains(definition), "This definiton has already been registered.");
        List<GUIModel> models = definition.getSlotStream()
                .flatMap(def -> def.getFeatures().values().stream())
                .map(GUIFeature::getModel)
                .distinct()
                .collect(Collectors.toList());
        definition.getSlotStream()
                .flatMap(def -> def.getFeatures().values().stream())
                .map(GUIFeature::getModel)
                .distinct()
                .forEach(SimpleCustomInventoryRegistry::registerGUIModelDurability);
        definitions.add(definition);
    }

    private static void registerGUIModelDurability(GUIModel model) {
        DurabilityRegistry.getInstance().register(
                model.getItemType(),
                model.getPluginContainer(),
                Collections.singleton(model.getModelName()),
                MODEL_DIRECTORY_NAME
        );
    }

    @Override
    public void generateResourcePackFiles(Path resourcePackDirectory) {
        Path guiDirectory = resourcePackDirectory.resolve("assets")
                .resolve(CustomItemLibrary.getInstance().getPluginContainer().getId())
                .resolve("models").resolve(MODEL_DIRECTORY_NAME);

        if(!Files.isDirectory(guiDirectory)) {
            try {
                Files.createDirectories(guiDirectory);
            } catch (IOException e) {
                CustomItemLibrary.getInstance().getLogger().error("Could not create the blocks directory.", e);
            }
        }

        definitions.stream()
                .flatMap(SimpleCustomInventoryDefinition::getSlotStream)
                .flatMap(slot -> slot.getFeatures().values().stream())
                .map(GUIFeature::getModel)
                .distinct()
                .forEach(guiModel -> {
                    Path modelFile = guiDirectory.resolve(guiModel.getModelName() + ".json");
                    JsonObject root = guiModel.createModelJson();

                    try(Writer writer = Files.newBufferedWriter(modelFile)) {
                        getGson().toJson(root, writer);
                    } catch (IOException e) {
                        CustomItemLibrary.getInstance().getLogger().error("Could not create model file: " + modelFile, e);
                    }
                });

        generateEmptyTexture(resourcePackDirectory);
    }

    /**
     * Keep the aspect ratio of textures
     */
    @Override
    public void writeAsset(SimpleCustomInventoryDefinition definition, String asset, ReadableByteChannel input, WritableByteChannel output, Path outputFile) throws IOException {
        if(!asset.endsWith(".png"))
            return;

        try (
                InputStream is = Channels.newInputStream(input);
                OutputStream os = Channels.newOutputStream(output)
        ) {
            BufferedImage originalImage = ImageIO.read(is);
            int largerDimension = originalImage.getWidth() > originalImage.getHeight() ? originalImage.getWidth() : originalImage.getHeight();
            BufferedImage correctedImage = new BufferedImage(largerDimension, largerDimension, originalImage.getType());
            Graphics correctedImageGraphics = correctedImage.createGraphics();

            correctedImageGraphics.drawImage(originalImage, 0, 0, null);
            ImageIO.write(correctedImage, "PNG", os);
        }
    }

    private void generateEmptyTexture(Path resourcePackDirectory) {
        Path texturePath = resourcePackDirectory.resolve("assets")
                .resolve(CustomItemLibrary.getInstance().getPluginContainer().getId())
                .resolve(GUIModel.EMPTY.getTextureId().getPath());

        BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);

        try {
            Files.createDirectories(texturePath.getParent());
            Files.deleteIfExists(texturePath);
            Files.createFile(texturePath);
            ImageIO.write(image, "PNG", texturePath.toFile());
        } catch (IOException e) {
            CustomItemLibrary.getInstance().getLogger().error("Could not create the empty texture.", e);
        }
    }

    public static SimpleCustomInventoryRegistry getInstance() {
        return INSTANCE;
    }
}

@@ -874,70 +874,11 @@
 til.
-List;%0Aimport java.util.Set;%0Aimport java.util.stream.Collectors
+Set
 ;%0A%0Ai
@@ -1697,254 +1697,8 @@
 %22);%0A
-        List%3CGUIModel%3E models = definition.getSlotStream()%0A                .flatMap(def -%3E def.getFeatures().values().stream())%0A                .map(GUIFeature::getModel)%0A                .distinct()%0A                .collect(Collectors.toList());%0A
     
@@ -2392,32 +2392,327 @@
 ackDirectory) %7B%0A
+        definitions.stream()%0A                .flatMap(SimpleCustomInventoryDefinition::getSlotStream)%0A                .flatMap(slot -%3E slot.getFeatures().values().stream())%0A                .map(GUIFeature::getModel)%0A                .distinct()%0A                .forEach(guiModel -%3E %7B%0A            
         Path gui
@@ -2783,48 +2783,37 @@
     
-.resolve(CustomItemLibrary.getInstance()
+            .resolve(guiModel
 .get
@@ -2831,32 +2831,44 @@
 iner().getId())%0A
+            
                 
@@ -2914,24 +2914,36 @@
 ORY_NAME);%0A%0A
+            
         if(!
@@ -2973,24 +2973,36 @@
 rectory)) %7B%0A
+            
             
@@ -3015,32 +3015,44 @@
                 
+     
+       
 Files.createDire
@@ -3078,32 +3078,44 @@
 y);%0A            
+         
+   
 %7D catch (IOExcep
@@ -3116,32 +3116,44 @@
 OException e) %7B%0A
+            
                 
@@ -3252,34 +3252,36 @@
 e);%0A            
-%7D%0A
+    
         %7D%0A%0A     
@@ -3278,291 +3278,30 @@
   %7D%0A
-%0A        definitions.stream()%0A                .flatMap(SimpleCustomInventoryDefinition::getSlotStream)%0A                .flatMap(slot -%3E slot.getFeatures().values().stream())%0A                .map(GUIFeature::getModel)%0A                .distinct()%0A                .forEach(guiModel -%3E %7B
+                    %7D%0A
 %0A   

fix GUI model generation directory