package com.seibel.lod.api.interfaces.override.worldGenerator;

import com.seibel.lod.api.enums.EDhApiDetailLevel;
import com.seibel.lod.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
import com.seibel.lod.api.enums.worldGeneration.EDhApiWorldGenThreadMode;
import com.seibel.lod.api.interfaces.override.IDhApiOverrideable;

import java.io.Closeable;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

/**
 * @author James Seibel
 * @version 2022-12-10
 */
public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
{
	//============//
	// parameters //
	//============//
	
	/** 
	 * Returns which thread chunk generation requests will be run on. <br>
	 * TODO: only {@link EDhApiWorldGenThreadMode#SINGLE_THREADED} is currently supported
	 */
	EDhApiWorldGenThreadMode getThreadingMode();
	
	/**
	 * Defines the smallest datapoint size that can be generated at a time. <br>
	 * Minimum detail level is 0 (1 block) <br>
	 * Default detail level is 0 <br>
	 * For more information on what detail levels represent see: {@link EDhApiDetailLevel}. <br><br>
	 * 
	 * TODO: System currently only supports 1x1 block per data.
	 * 
	 * @see	EDhApiDetailLevel
	 */
	default byte getMinDataDetailLevel() { return EDhApiDetailLevel.BLOCK.detailLevel; }
	/**
	 * Defines the largest datapoint size that can be generated at a time. <br>
	 * Minimum detail level is 0 (1 block) <br>
	 * Default detail level is 0 <br>
	 * For more information on what detail levels represent see: {@link EDhApiDetailLevel}.
	 * 
	 * @see	EDhApiDetailLevel
	 */
	default byte getMaxDataDetailLevel() { return EDhApiDetailLevel.BLOCK.detailLevel; }
	
	/**
	 * When creating generation requests the system will attempt to group nearby tasks together. <br><br>
	 * What is the minimum size a single generation call can batch together? <br>
	 * 
	 * Minimum detail level is 4 (the size of a MC chunk) <br>
	 * Default detail level is 4 <br>
	 * For more information on what detail levels represent see: {@link EDhApiDetailLevel}.
	 * 
	 * @see	EDhApiDetailLevel
	 */
	default byte getMinGenerationGranularity() { return EDhApiDetailLevel.CHUNK.detailLevel; }
	
	/**
	 * When creating generation requests the system will attempt to group nearby tasks together. <br><br>
	 * What is the maximum size a single generation call can batch together? <br>
	 * 
	 * Minimum detail level is 4 (the size of a MC chunk) <br>
	 * Default detail level is 6 (4x4 chunks) <br>
	 * For more information on what detail levels represent see: {@link EDhApiDetailLevel}.
	 *  
	 * @see	EDhApiDetailLevel
	 */
	default byte getMaxGenerationGranularity() { return (byte) (EDhApiDetailLevel.CHUNK.detailLevel + 2); }
	
	/** Returns true if the generator is unable to accept new generation requests. */
	boolean isBusy();
	
	
	
	
	//=================//
	// world generator //
	//=================//
	
	/**
	 * This method is called by Distant Horizons to generate terrain over a given area
	 * from a thread defined by {@link IDhApiWorldGenerator#getThreadingMode}. <br><br>
	 * 
	 * After a chunk has been generated it (and any necessary supporting objects as listed below) should be passed into the 
	 * resultConsumer's {@link Consumer#accept} method. If the Consumer is given the wrong data
	 * type(s) it will throw a {@link ClassCastException} with a list of what objects it was expecting. <br>
	 * <strong>Note:</strong> these objects are minecraft version dependent and will change without notice!
	 * Please run your generator in game at least once to confirm the objects you are returning are correct. <br><br>
	 * 
	 * Consumer expected inputs for each minecraft version (in order): <br>
	 * <strong>1.18:</strong> {@link net.minecraft.world.level.chunk.ChunkAccess} and {@link net.minecraft.world.level.LevelReader} <br>
	 * 
	 * @throws ClassCastException if incompatible objects are passed into the resultConsumer.
	 */
	CompletableFuture<Void> generateChunks(int chunkPosMinX, int chunkPosMinZ,
			byte granularity, byte targetDataDetail, EDhApiDistantGeneratorMode generatorMode,
			Consumer<Object[]> resultConsumer) throws ClassCastException;
	
	
	
	//===============//
	// event methods //
	//===============//
	
	/**
	 * Called before a new generator task is started. <br>
	 * This can be used to run cleanup on existing tasks before new tasks are started.
	 */
	void preGeneratorTaskStart();
	
	
	
	//===========//
	// overrides //
	//===========//
	
	// This is overridden to remove the "throws IOException" 
	// that is present in the default Closeable.close() method 
	@Override
	void close();
	
	
}
