package net.Chipperfluff.chipi.world.gen;

import net.minecraft.block.BlockState;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;

import net.Chipperfluff.chipi.world.gen.struct.CorridorEWStructure;
import net.Chipperfluff.chipi.world.gen.struct.CorridorNSStructure;
import net.Chipperfluff.chipi.world.gen.struct.RoomBaseStructure;

public class ChipiDungeonGenerator {

    // Structure extents from NBT sizes (centered)
    private static final int ROOM_EXTENT_SOUTH = 8;
    private static final int ROOM_EXTENT_NORTH = 8;
    private static final int ROOM_EXTENT_EAST = 7;
    private static final int ROOM_EXTENT_WEST = 9;

    // Fixed Y-levels
    private static final int ROOM_Y = 89;
    private static final int CORRIDOR_Y = 89;

    // Corridors are 10 long; they should overwrite 1 block into each room (-1 on both ends).
    private static final int CORRIDOR_LENGTH = 10;

    // Center-to-center step so corridors start 1 block inside the north room and end 1 block inside
    // the south room.
    private static final int STEP_Z = ROOM_EXTENT_SOUTH + CORRIDOR_LENGTH + ROOM_EXTENT_NORTH - 1; // 25
    private static final int STEP_X = ROOM_EXTENT_EAST + CORRIDOR_LENGTH + ROOM_EXTENT_WEST - 1; // 25

    private static final int ROWS_SOUTH = 40; // rows of rooms south of spawn (spawn room itself is already placed)
    private static final int COLS_EW = 40; // columns across X (split roughly evenly around center)

    private ChipiDungeonGenerator() {}

    public static void generateInitialLayout(ServerWorld world, BlockPos portalSpawnPos) {

        // Spawn is already placed. Fixed anchors (not relative to portal):
        // first corridor origin, then the first generated room center is south of spawn.
        BlockPos firstCorridorAnchor = new BlockPos(5, CORRIDOR_Y, 11);
        BlockPos firstGeneratedRoomCenter = new BlockPos(5, ROOM_Y, 24); // explicit first floor anchor

        // First room/corridor use direct instances as requested.
        RoomBaseStructure firstRoom = WorldMaster.getDefaultRoom();
        CorridorNSStructure firstCorridor = WorldMaster.getDefaultCorridorNS();

        // Place the first room (absolute coordinates).
        firstRoom.placeAt(world, firstGeneratedRoomCenter);

        // Place the fixed corridor leaving spawn intact.
        firstCorridor.placeAt(world, firstCorridorAnchor);

        // Column range centered on x=5 for a 40-wide grid (approx. 20 each side).
        int minCol = -(COLS_EW / 2) + 1; // -19 for 40 cols -> -19..20 inclusive
        int maxCol = (COLS_EW / 2); // 20

        // Place rooms strictly southward (Z never decreases), across X in both directions.
        for (int row = 0; row < ROWS_SOUTH; row++) {
            for (int col = minCol; col <= maxCol; col++) {
                int gridX = col; // grid 0,0 is the first generated room; -X -> negative gridX, +X -> positive gridX
                int gridY = row; // gridY increases southward only

                BlockPos center = new BlockPos(
                    firstGeneratedRoomCenter.getX() + (col * STEP_X),
                    ROOM_Y,
                    firstGeneratedRoomCenter.getZ() + (row * STEP_Z)
                );

                RoomBaseStructure room = WorldMaster.resolveRoom(ctx(world, gridX, gridY, center, null));
                room.placeAt(world, center);
                WorldMaster.afterPlaceRoom(ctx(world, gridX, gridY, center, room));
            }
        }

        // Connect each room to the next one south with a corridor at fixed Y (no northward
        // connections).
        for (int row = 0; row < ROWS_SOUTH - 1; row++) {
            for (int col = minCol; col <= maxCol; col++) {
                int gridX = col;
                int gridY = row;

                BlockPos currentCenter = new BlockPos(
                    firstGeneratedRoomCenter.getX() + (col * STEP_X),
                    ROOM_Y,
                    firstGeneratedRoomCenter.getZ() + (row * STEP_Z)
                );

                BlockPos anchorSouth = new BlockPos(
                    currentCenter.getX(),
                    CORRIDOR_Y,
                    currentCenter.getZ() + ROOM_EXTENT_SOUTH
                );

                CorridorNSStructure corridorNS = WorldMaster.resolveCorridorNS(ctx(world, gridX, gridY, anchorSouth, null));
                corridorNS.placeAt(world, anchorSouth);
                WorldMaster.afterPlaceCorridorNS(ctx(world, gridX, gridY, anchorSouth, corridorNS));
            }
        }

        // Connect east-west neighbors in each row.
        for (int row = 0; row < ROWS_SOUTH; row++) {
            for (int col = minCol; col < maxCol; col++) {
                int gridX = col;
                int gridY = row;

                BlockPos currentCenter = new BlockPos(
                    firstGeneratedRoomCenter.getX() + (col * STEP_X),
                    ROOM_Y,
                    firstGeneratedRoomCenter.getZ() + (row * STEP_Z)
                );

                BlockPos anchorEast = new BlockPos(
                    currentCenter.getX() + ROOM_EXTENT_EAST,
                    CORRIDOR_Y,
                    currentCenter.getZ()
                );

                CorridorEWStructure corridorEW = WorldMaster.resolveCorridorEW(ctx(world, gridX, gridY, anchorEast, null));
                corridorEW.placeAt(world, anchorEast);
                WorldMaster.afterPlaceCorridorEW(ctx(world, gridX, gridY, anchorEast, corridorEW));
            }
        }

        cleanUpEntrance(world);
    }

    /** Runs the post-placement cleanup/decoration around spawn and first room. */
    private static void cleanUpEntrance(ServerWorld world) {

        runInChipi(world, "fill 7 87 15 3 91 16 minecraft:air");

        runInChipi(world, "setblock 4 88 15 minecraft:deepslate_tile_stairs[facing=west,waterlogged=true]");
        runInChipi(world, "setblock 4 88 16 minecraft:deepslate_tile_stairs[facing=west,waterlogged=true]");
        runInChipi(world, "setblock 6 88 15 minecraft:deepslate_tile_stairs[facing=east,waterlogged=true]");
        runInChipi(world, "setblock 6 88 16 minecraft:deepslate_tile_stairs[facing=east,waterlogged=true]");

        runInChipi(world, "fill 7 88 15 7 91 16 minecraft:deepslate_tiles");
        runInChipi(world, "fill 3 88 16 3 91 15 minecraft:deepslate_tiles");

        runInChipi(world, "setblock 4 90 15 minecraft:deepslate_tile_stairs[facing=west,half=top]");
        runInChipi(world, "setblock 4 90 16 minecraft:deepslate_tile_stairs[facing=west,half=top]");
        runInChipi(world, "setblock 6 90 15 minecraft:deepslate_tile_stairs[facing=east,half=top]");
        runInChipi(world, "setblock 6 90 16 minecraft:deepslate_tile_stairs[facing=east,half=top]");

        runInChipi(world, "fill 5 88 15 5 87 16 minecraft:deepslate_tile_slab[waterlogged=true]");
        runInChipi(world, "fill 5 91 16 5 91 15 minecraft:deepslate_tiles");
    }

    private static void fillBox(ServerWorld world, int x1, int y1, int z1, int x2, int y2, int z2, BlockState state) {
        int minX = Math.min(x1, x2);
        int maxX = Math.max(x1, x2);
        int minY = Math.min(y1, y2);
        int maxY = Math.max(y1, y2);
        int minZ = Math.min(z1, z2);
        int maxZ = Math.max(z1, z2);

        for (int x = minX; x <= maxX; x++) {
            for (int y = minY; y <= maxY; y++) {
                for (int z = minZ; z <= maxZ; z++) {
                    world.setBlockState(new BlockPos(x, y, z), state, 3);
                }
            }
        }
    }

    private static void runInChipi(ServerWorld world, String command) {
        world.getServer()
            .getCommandManager()
            .executeWithPrefix(
                world.getServer().getCommandSource(),
                "execute in chipi:chipi_dimension run " + command
            );
    }

    private static DungeonContext ctx(ServerWorld world, int gridX, int gridY, BlockPos origin, ChipiStructure structure) {
        return DungeonContext.of(world, gridX, gridY, origin, structure);
    }
}
