package speiger.src.coreengine.utils.profiler;

import java.util.function.ObjIntConsumer;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.utils.helpers.TextUtil;

public interface IProfiler
{
	public String getName();
	public IProfilerEntry getEntry(String name);
	public long getTicksRan();
	public void enable();
	public void disable();
	
	public default void setState(boolean enabled) {
		if(enabled) enable();
		else disable();
	}
	
	public boolean isEnabled();
	public void addListener(ObjIntConsumer<IProfiler> listener);
	public void removeListener(ObjIntConsumer<IProfiler> listener);
	public IProfiler start(String name);
	public IProfiler start(Class<?> clz);
	public IProfiler stop();
	public IProfiler next(String name);
	public void onFrameEnded(boolean count);
	
	public static interface IProfilerEntry
	{
		public String getName();		
		public default String getPathName() { return getName(); }
		public long getMinTime();
		public long getNanoTime();
		public long getMaxTime();
		public int getDebth();
		public int getChildCount();
		public IProfilerEntry getChild(int index);
		public IProfilerEntry getParent();
		public IProfiler getOwner();
		
		default long getTotalTime() {
			IProfilerEntry entry = this;
			while(entry.getParent() != null) {
				entry = entry.getParent();
			}
			return entry.getNanoTime();
		}
		
		public default ObjectList<ProfilerData> getData() {
			ObjectList<ProfilerData> list = new ObjectArrayList<>();
			long time = getNanoTime();
			long totalTime = getTotalTime();
			long used = 0L;
			for(int i = 0;i<getChildCount();i++) {
				IProfilerEntry child = getChild(i);
				long nanoTime = child.getNanoTime();
				used += nanoTime;
				double percent = (((double)nanoTime / (double)time) * 100D);
				double totalPercent = (((double)nanoTime / (double)totalTime) * 100D);
				list.add(new ProfilerData(child.getName(), nanoTime, percent, totalPercent));
			}
			if(used < time) {
				long nanoTime = time - used;
				double percent = (((double)nanoTime / (double)time) * 100D);
				double totalPercent = (((double)nanoTime / (double)totalTime) * 100D);
				list.add(new ProfilerData("self", nanoTime, percent, totalPercent));
			}
			list.sort(null);
			return list;
		}
	}
	
	public static record ProfilerData(String name, int color, long nanoTime, double effect, double totalEffect) implements Comparable<ProfilerData>
	{
		public ProfilerData(String name, long time, double effect, double totalEffect) {
			this(name, TextUtil.getColorFromText(name), time, effect, totalEffect);
		}
		
		@Override
		public int compareTo(ProfilerData o) {
			if(o.nanoTime > nanoTime) return 1;
			return o.nanoTime < nanoTime ? -1 : name.compareTo(o.name);
		}
	}
}
