package net.minecraft.gametest.framework;

import org.apache.logging.log4j.LogManager;
import net.minecraft.world.level.block.entity.StructureBlockEntity;
import net.minecraft.core.Vec3i;
import net.minecraft.world.phys.AABB;
import java.util.Iterator;
import com.google.common.collect.Maps;
import com.google.common.collect.Lists;
import net.minecraft.world.level.block.Rotation;
import java.util.Collection;
import com.mojang.datafixers.util.Pair;
import java.util.Map;
import java.util.List;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.core.BlockPos;
import org.apache.logging.log4j.Logger;

public class GameTestBatchRunner {
    private static final Logger LOGGER;
    private final BlockPos firstTestNorthWestCorner;
    private final ServerLevel level;
    private final GameTestTicker testTicker;
    private final int testsPerRow;
    private final List<GameTestInfo> allTestInfos;
    private final Map<GameTestInfo, BlockPos> northWestCorners;
    private final List<Pair<GameTestBatch, Collection<GameTestInfo>>> batches;
    private MultipleTestTracker currentBatchTracker;
    private int currentBatchIndex;
    private BlockPos.MutableBlockPos nextTestNorthWestCorner;
    
    public GameTestBatchRunner(final Collection<GameTestBatch> collection, final BlockPos fu, final Rotation cap, final ServerLevel zd, final GameTestTicker km, final int integer) {
        this.allTestInfos = Lists.newArrayList();
        this.northWestCorners = Maps.newHashMap();
        this.batches = Lists.newArrayList();
        this.currentBatchIndex = 0;
        this.nextTestNorthWestCorner = fu.mutable();
        this.firstTestNorthWestCorner = fu;
        this.level = zd;
        this.testTicker = km;
        this.testsPerRow = integer;
        final Collection<GameTestInfo> collection2;
        final Collection<TestFunction> collection3;
        final Iterator<TestFunction> iterator;
        TestFunction kv8;
        GameTestInfo kg9;
        collection.forEach(kb -> {
            collection2 = Lists.newArrayList();
            collection3 = kb.getTestFunctions();
            collection3.iterator();
            while (iterator.hasNext()) {
                kv8 = iterator.next();
                kg9 = new GameTestInfo(kv8, cap, zd);
                collection2.add(kg9);
                this.allTestInfos.add(kg9);
            }
            this.batches.add((Pair<GameTestBatch, Collection<GameTestInfo>>)Pair.of(kb, collection2));
        });
    }
    
    public List<GameTestInfo> getTestInfos() {
        return this.allTestInfos;
    }
    
    public void start() {
        this.runBatch(0);
    }
    
    private void runBatch(final int integer) {
        this.currentBatchIndex = integer;
        this.currentBatchTracker = new MultipleTestTracker();
        if (integer >= this.batches.size()) {
            return;
        }
        final Pair<GameTestBatch, Collection<GameTestInfo>> pair3 = this.batches.get(this.currentBatchIndex);
        final GameTestBatch kb4 = (GameTestBatch)pair3.getFirst();
        final Collection<GameTestInfo> collection5 = (Collection<GameTestInfo>)pair3.getSecond();
        this.createStructuresForBatch(collection5);
        kb4.runBeforeBatchFunction(this.level);
        final String string6 = kb4.getName();
        GameTestBatchRunner.LOGGER.info("Running test batch '" + string6 + "' (" + collection5.size() + " tests)...");
        final BlockPos fu3;
        collection5.forEach(kg -> {
            this.currentBatchTracker.addTestToTrack(kg);
            this.currentBatchTracker.addListener(new GameTestListener() {
                @Override
                public void testStructureLoaded(final GameTestInfo kg) {
                }
                
                @Override
                public void testFailed(final GameTestInfo kg) {
                    GameTestBatchRunner.this.testCompleted(kg);
                }
            });
            fu3 = this.northWestCorners.get(kg);
            GameTestRunner.runTest(kg, fu3, this.testTicker);
        });
    }
    
    private void testCompleted(final GameTestInfo kg) {
        if (this.currentBatchTracker.isDone()) {
            this.runBatch(this.currentBatchIndex + 1);
        }
    }
    
    private void createStructuresForBatch(final Collection<GameTestInfo> collection) {
        int integer3 = 0;
        AABB deg4 = new AABB(this.nextTestNorthWestCorner);
        for (final GameTestInfo kg6 : collection) {
            final BlockPos fu7 = new BlockPos(this.nextTestNorthWestCorner);
            final StructureBlockEntity cel8 = StructureUtils.spawnStructure(kg6.getStructureName(), fu7, kg6.getRotation(), 2, this.level, true);
            final AABB deg5 = StructureUtils.getStructureBounds(cel8);
            kg6.setStructureBlockPos(cel8.getBlockPos());
            this.northWestCorners.put(kg6, new BlockPos(this.nextTestNorthWestCorner));
            deg4 = deg4.minmax(deg5);
            this.nextTestNorthWestCorner.move((int)deg5.getXsize() + 5, 0, 0);
            if (integer3++ % this.testsPerRow == this.testsPerRow - 1) {
                this.nextTestNorthWestCorner.move(0, 0, (int)deg4.getZsize() + 6);
                this.nextTestNorthWestCorner.setX(this.firstTestNorthWestCorner.getX());
                deg4 = new AABB(this.nextTestNorthWestCorner);
            }
        }
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
}
