package electrosphere.util;

import electrosphere.logger.LoggerInterface;
import electrosphere.main.Globals;
import electrosphere.main.Main;
import electrosphere.renderer.Material;
import electrosphere.renderer.Mesh;
import electrosphere.renderer.Model;
import electrosphere.renderer.texture.Texture;
import electrosphere.renderer.texture.TextureMap;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.assimp.AIScene;
import static org.lwjgl.assimp.Assimp.*;
import static org.lwjgl.assimp.Assimp.aiImportFile;

public class ModelLoader {
    public static Model load_Model_From_File(String fileName){
        Model rVal;
        AIScene scene;
//        File file = new File(Thread.currentThread().getContextClassLoader().getResource(fileName).getFile());
//        Main.class.getResourceAsStream(fileName).readAllBytes();
        File toRead = FileUtils.getAssetFile(fileName);
        scene = aiImportFile(toRead.getAbsolutePath(), 
                        aiProcess_GenSmoothNormals | 
                        aiProcess_JoinIdenticalVertices | 
                        aiProcess_Triangulate | 
                        aiProcess_FixInfacingNormals | 
                        aiProcess_LimitBoneWeights);
        if(scene == null){
            throw new IllegalStateException(aiGetErrorString());
        }
        rVal = Model.createModelFromAiscene(scene);
        attemptAddTexturesFromPathname(fileName, rVal);
        return rVal;
    }
    
    //TODO: this logic should exclusively use functions provided in the TextureMap class
    //this way if we change the underlying structure of the TextureMap it doesn't fuck over this logic
    static void attemptAddTexturesFromPathname(String path, Model m){
        //first we get the default texture map that's global
        TextureMap global_map = Globals.textureMapDefault;
        LoggerInterface.loggerRenderer.DEBUG(path);
        //then we try to get the path of our model from the map
        Map<String,ArrayList<String>> mesh_map = global_map.get_mesh_map(path);
        //if it exists..
        if(mesh_map != null){
            //iterate through each mesh in the model that was provided as input
            Iterator<Mesh> mesh_iterator = m.meshes.iterator();
            while(mesh_iterator.hasNext()){
                Mesh current_mesh = mesh_iterator.next();
                LoggerInterface.loggerRenderer.DEBUG(current_mesh.nodeID);
                //if the current iteration is contained within the mesh map we procured from above
                if(mesh_map.containsKey(current_mesh.nodeID)){
                    //we create a new material, check if the diffuse or specular is not null,
                    //and if they aren't we add that path as a new texture of respective type to the material
                    Material final_material = new Material();
                    ArrayList<String> texture_path_list = mesh_map.get(current_mesh.nodeID);
                    String diffuse_path = TextureMap.get_diffuse_path(texture_path_list);
                    LoggerInterface.loggerRenderer.DEBUG(current_mesh.nodeID + "->" + diffuse_path);
                    if(diffuse_path != null){
                        LoggerInterface.loggerRenderer.DEBUG(diffuse_path);
//                        Texture diffuse = new Texture(diffuse_path);
                        Globals.assetManager.addTexturePathtoQueue(diffuse_path);
                        final_material.set_diffuse(diffuse_path);
                        LoggerInterface.loggerRenderer.DEBUG(diffuse_path);
                    } else {
                        final_material.set_diffuse(Globals.textureDiffuseDefault);
                    }
                    String specular_path = TextureMap.get_specular_path(texture_path_list);
                    if(specular_path != null){
//                        Texture specular = new Texture(specular_path);
                        Globals.assetManager.addTexturePathtoQueue(specular_path);
                        final_material.set_specular(specular_path);
                        LoggerInterface.loggerRenderer.DEBUG(specular_path);
                    } else {
                        final_material.set_specular(Globals.textureSpecularDefault);
                    }
                    //once we've either added default textures or actual textures,
                    //set the current mesh's material to this new one
                    current_mesh.setMaterial(final_material);
                } else {
                    LoggerInterface.loggerRenderer.WARNING("Failed to load texture for node " + current_mesh.nodeID + " of model " + path);
                }
            }
        }
    }
}
