package com.tiedup.remake.commands;

import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.tiedup.remake.blocks.entity.MarkerBlockEntity;
import com.tiedup.remake.cells.CellDataV2;
import com.tiedup.remake.cells.CellOwnerType;
import com.tiedup.remake.cells.CellRegistryV2;
import com.tiedup.remake.items.ItemAdminWand;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import net.minecraft.ChatFormatting;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;

/**
 * Cell management commands.
 *
 * Phase: Kidnapper Revamp - Cell System
 *
 * Commands:
 *   /tiedup cell name <name>     - Name the selected cell (from wand) and link to player
 *   /tiedup cell list [owner]    - List all cells, optionally filtered by owner
 *   /tiedup cell info [name]     - Show info about selected cell or by name
 *   /tiedup cell delete          - Delete the selected cell
 *
 * Requires OP level 2.
 */
public class CellCommand {

    /**
     * Create the cell command builder (for use as subcommand of /tiedup).
     */
    public static com.mojang.brigadier.builder.LiteralArgumentBuilder<
        CommandSourceStack
    > createCellCommand() {
        return Commands.literal("cell")
            .requires(CommandHelper.REQUIRES_OP)
            // /tiedup cell name <name>
            .then(
                Commands.literal("name").then(
                    Commands.argument(
                        "name",
                        StringArgumentType.word()
                    ).executes(CellCommand::setName)
                )
            )
            // /tiedup cell list [owner]
            .then(
                Commands.literal("list")
                    .executes(CellCommand::listAll)
                    .then(
                        Commands.argument(
                            "owner",
                            EntityArgument.player()
                        ).executes(CellCommand::listByOwner)
                    )
            )
            // /tiedup cell info [name]
            .then(
                Commands.literal("info")
                    .executes(CellCommand::infoSelected)
                    .then(
                        Commands.argument(
                            "name",
                            StringArgumentType.word()
                        ).executes(CellCommand::infoByName)
                    )
            )
            // /tiedup cell delete
            .then(
                Commands.literal("delete").executes(CellCommand::deleteSelected)
            )
            // /tiedup cell resetspawns [radius]
            .then(
                Commands.literal("resetspawns")
                    .executes(ctx -> resetSpawns(ctx, 100)) // Default 100 block radius
                    .then(
                        Commands.argument(
                            "radius",
                            IntegerArgumentType.integer(1, 500)
                        ).executes(ctx ->
                            resetSpawns(
                                ctx,
                                IntegerArgumentType.getInteger(ctx, "radius")
                            )
                        )
                    )
            );
    }

    /**
     * /tiedup cell name <name>
     *
     * Name the selected cell (from wand) and link it to the executing player.
     */
    private static int setName(CommandContext<CommandSourceStack> context)
        throws CommandSyntaxException {
        CommandSourceStack source = context.getSource();
        String name = StringArgumentType.getString(context, "name");

        // Must be a player
        if (!(source.getEntity() instanceof ServerPlayer player)) {
            source.sendFailure(Component.translatable("command.tiedup.error.must_be_player"));
            return 0;
        }

        ServerLevel serverLevel = player.serverLevel();
        CellRegistryV2 registry = CellRegistryV2.get(serverLevel);

        // Get selected cell from wand
        UUID selectedCellId = getSelectedCellFromWand(player);
        if (selectedCellId == null) {
            source.sendFailure(
                Component.translatable("command.tiedup.cell.no_selection")
            );
            return 0;
        }

        CellDataV2 cell = registry.getCell(selectedCellId);
        if (cell == null) {
            source.sendFailure(
                Component.translatable("command.tiedup.cell.no_longer_exists")
            );
            return 0;
        }

        // Check name uniqueness
        CellDataV2 existingCell = registry.getCellByName(name);
        if (
            existingCell != null && !existingCell.getId().equals(selectedCellId)
        ) {
            source.sendFailure(
                Component.translatable("command.tiedup.cell.name_exists", name)
            );
            return 0;
        }

        // Set name and owner
        cell.setName(name);

        // MEDIUM FIX: Update camp index when changing ownership
        // Store old ownerId before changing (in case it was camp-owned)
        UUID oldOwnerId = cell.isCampOwned() ? cell.getOwnerId() : null;
        cell.setOwnerId(player.getUUID());
        cell.setOwnerType(CellOwnerType.PLAYER);
        registry.updateCampIndex(cell, oldOwnerId);

        registry.setDirty();

        source.sendSuccess(
            () ->
                Component.translatable("command.tiedup.cell.named", name).withStyle(ChatFormatting.GREEN),
            true
        );
        return 1;
    }

    /**
     * /tiedup cell list
     *
     * List all registered cells.
     */
    private static int listAll(CommandContext<CommandSourceStack> context) {
        CommandSourceStack source = context.getSource();
        ServerLevel serverLevel = source.getLevel();
        CellRegistryV2 registry = CellRegistryV2.get(serverLevel);

        Collection<CellDataV2> cells = registry.getAllCells();
        if (cells.isEmpty()) {
            source.sendSuccess(
                () -> Component.translatable("command.tiedup.cell.none_registered"),
                false
            );
            return 1;
        }

        source.sendSuccess(
            () -> Component.translatable("command.tiedup.cell.list_header", cells.size()).withStyle(ChatFormatting.GOLD),
            false
        );

        for (CellDataV2 cell : cells) {
            String info = formatCellInfo(cell, serverLevel);
            source.sendSuccess(() -> Component.literal(info).withStyle(ChatFormatting.GRAY), false);
        }

        return 1;
    }

    /**
     * /tiedup cell list <owner>
     *
     * List cells owned by a specific player.
     */
    private static int listByOwner(CommandContext<CommandSourceStack> context)
        throws CommandSyntaxException {
        CommandSourceStack source = context.getSource();
        ServerPlayer owner = EntityArgument.getPlayer(context, "owner");
        ServerLevel serverLevel = source.getLevel();
        CellRegistryV2 registry = CellRegistryV2.get(serverLevel);

        List<CellDataV2> cells = registry.getCellsByOwner(owner.getUUID());
        if (cells.isEmpty()) {
            source.sendSuccess(
                () ->
                    Component.translatable("command.tiedup.cell.no_cells_for_owner", owner.getName().getString()),
                false
            );
            return 1;
        }

        source.sendSuccess(
            () ->
                Component.translatable(
                    "command.tiedup.cell.list_owner_header",
                    owner.getName().getString(),
                    cells.size()
                ).withStyle(ChatFormatting.GOLD),
            false
        );

        for (CellDataV2 cell : cells) {
            String info = formatCellInfo(cell, serverLevel);
            source.sendSuccess(() -> Component.literal(info).withStyle(ChatFormatting.GRAY), false);
        }

        return 1;
    }

    /**
     * /tiedup cell info
     *
     * Show info about the selected cell (from wand).
     */
    private static int infoSelected(
        CommandContext<CommandSourceStack> context
    ) {
        CommandSourceStack source = context.getSource();

        // Must be a player
        if (!(source.getEntity() instanceof ServerPlayer player)) {
            source.sendFailure(Component.translatable("command.tiedup.error.must_be_player"));
            return 0;
        }

        ServerLevel serverLevel = player.serverLevel();
        CellRegistryV2 registry = CellRegistryV2.get(serverLevel);

        UUID selectedCellId = getSelectedCellFromWand(player);
        if (selectedCellId == null) {
            source.sendFailure(
                Component.translatable("command.tiedup.cell.no_selection")
            );
            return 0;
        }

        CellDataV2 cell = registry.getCell(selectedCellId);
        if (cell == null) {
            source.sendFailure(
                Component.translatable("command.tiedup.cell.no_longer_exists")
            );
            return 0;
        }

        displayCellInfo(source, cell, serverLevel);
        return 1;
    }

    /**
     * /tiedup cell info <name>
     *
     * Show info about a cell by name.
     */
    private static int infoByName(CommandContext<CommandSourceStack> context) {
        CommandSourceStack source = context.getSource();
        String name = StringArgumentType.getString(context, "name");
        ServerLevel serverLevel = source.getLevel();
        CellRegistryV2 registry = CellRegistryV2.get(serverLevel);

        CellDataV2 cell = registry.getCellByName(name);
        if (cell == null) {
            source.sendFailure(
                Component.translatable("command.tiedup.cell.not_found", name)
            );
            return 0;
        }

        displayCellInfo(source, cell, serverLevel);
        return 1;
    }

    /**
     * /tiedup cell delete
     *
     * Delete the selected cell (from wand).
     */
    private static int deleteSelected(
        CommandContext<CommandSourceStack> context
    ) {
        CommandSourceStack source = context.getSource();

        // Must be a player
        if (!(source.getEntity() instanceof ServerPlayer player)) {
            source.sendFailure(Component.translatable("command.tiedup.error.must_be_player"));
            return 0;
        }

        ServerLevel serverLevel = player.serverLevel();
        CellRegistryV2 registry = CellRegistryV2.get(serverLevel);

        UUID selectedCellId = getSelectedCellFromWand(player);
        if (selectedCellId == null) {
            source.sendFailure(
                Component.translatable("command.tiedup.cell.no_selection")
            );
            return 0;
        }

        CellDataV2 cell = registry.getCell(selectedCellId);
        if (cell == null) {
            source.sendFailure(
                Component.translatable("command.tiedup.cell.no_longer_exists")
            );
            return 0;
        }

        String cellName =
            cell.getName() != null
                ? cell.getName()
                : cell.getId().toString().substring(0, 8) + "...";

        // Remove cell from registry
        registry.removeCell(selectedCellId);

        // Clear selection from wand
        ItemStack mainHand = player.getMainHandItem();
        if (mainHand.getItem() instanceof ItemAdminWand) {
            ItemAdminWand.setActiveCellId(mainHand, null);
        }
        ItemStack offHand = player.getOffhandItem();
        if (offHand.getItem() instanceof ItemAdminWand) {
            ItemAdminWand.setActiveCellId(offHand, null);
        }

        source.sendSuccess(
            () -> Component.translatable("command.tiedup.cell.deleted", cellName).withStyle(ChatFormatting.GREEN),
            true
        );
        return 1;
    }

    /**
     * /tiedup cell resetspawns [radius]
     *
     * Reset the hasSpawned flag on all spawn markers within radius.
     * Use this before saving a structure to ensure NPCs will spawn when placed.
     *
     * Performance: Iterates over loaded chunks and their BlockEntities instead of
     * individual block positions to avoid server crash on large radii.
     */
    private static int resetSpawns(
        CommandContext<CommandSourceStack> context,
        int radius
    ) {
        CommandSourceStack source = context.getSource();
        ServerLevel serverLevel = source.getLevel();
        BlockPos center = BlockPos.containing(source.getPosition());

        int resetCount = 0;
        int spawnMarkerCount = 0;

        // Convert block radius to chunk radius (16 blocks per chunk)
        int chunkRadius = (radius + 15) >> 4;
        int centerChunkX = center.getX() >> 4;
        int centerChunkZ = center.getZ() >> 4;

        // Iterate over chunks instead of individual blocks (much faster)
        for (
            int cx = centerChunkX - chunkRadius;
            cx <= centerChunkX + chunkRadius;
            cx++
        ) {
            for (
                int cz = centerChunkZ - chunkRadius;
                cz <= centerChunkZ + chunkRadius;
                cz++
            ) {
                // Only process loaded chunks
                net.minecraft.world.level.chunk.LevelChunk chunk = serverLevel
                    .getChunkSource()
                    .getChunkNow(cx, cz);
                if (chunk == null) continue;

                // Iterate over all BlockEntities in this chunk
                for (BlockEntity be : chunk.getBlockEntities().values()) {
                    if (!(be instanceof MarkerBlockEntity marker)) continue;

                    // Check if within radius (squared distance for performance)
                    BlockPos pos = be.getBlockPos();
                    double distSq = center.distSqr(pos);
                    if (distSq > (double) radius * radius) continue;

                    if (marker.isSpawnMarker()) {
                        spawnMarkerCount++;
                        if (marker.hasSpawned()) {
                            marker.resetHasSpawned();
                            resetCount++;
                        }
                    }
                }
            }
        }

        final int finalResetCount = resetCount;
        final int finalSpawnMarkerCount = spawnMarkerCount;

        source.sendSuccess(
            () ->
                Component.translatable(
                    "command.tiedup.cell.reset_spawns", finalResetCount, finalSpawnMarkerCount, radius
                ).withStyle(ChatFormatting.GREEN),
            true
        );

        if (resetCount > 0) {
            source.sendSuccess(
                () ->
                    Component.translatable("command.tiedup.cell.reset_spawns_hint").withStyle(ChatFormatting.GRAY),
                false
            );
        }

        return 1;
    }

    // ==================== HELPERS ====================

    /**
     * Get the selected cell ID from the player's admin wand.
     */
    private static UUID getSelectedCellFromWand(ServerPlayer player) {
        // Check main hand
        ItemStack mainHand = player.getMainHandItem();
        if (mainHand.getItem() instanceof ItemAdminWand) {
            UUID cellId = ItemAdminWand.getActiveCellId(mainHand);
            if (cellId != null) return cellId;
        }

        // Check offhand
        ItemStack offHand = player.getOffhandItem();
        if (offHand.getItem() instanceof ItemAdminWand) {
            return ItemAdminWand.getActiveCellId(offHand);
        }

        return null;
    }

    /**
     * Format cell info for list display.
     */
    private static String formatCellInfo(CellDataV2 cell, ServerLevel level) {
        StringBuilder sb = new StringBuilder();

        // Name or ID
        if (cell.getName() != null) {
            sb.append("  ").append(cell.getName());
        } else {
            sb
                .append("  ")
                .append(cell.getId().toString().substring(0, 8))
                .append("...");
        }

        // Position
        sb.append(" @ ").append(cell.getCorePos().toShortString());

        // Owner
        if (cell.hasOwner()) {
            ServerPlayer owner = level
                .getServer()
                .getPlayerList()
                .getPlayer(cell.getOwnerId());
            if (owner != null) {
                sb.append(" (").append(owner.getName().getString()).append(")");
            } else {
                sb.append(" (offline)");
            }
        } else {
            sb.append(" (world)");
        }

        // Prisoners
        if (cell.isOccupied()) {
            sb
                .append(" [")
                .append(cell.getPrisonerCount())
                .append(" prisoners]");
        }

        return sb.toString();
    }

    /**
     * Display detailed cell info (V2).
     */
    private static void displayCellInfo(
        CommandSourceStack source,
        CellDataV2 cell,
        ServerLevel level
    ) {
        String nameDisplay =
            cell.getName() != null ? cell.getName() : "(unnamed)";
        source.sendSuccess(
            () -> Component.translatable("command.tiedup.cell.info_header", nameDisplay).withStyle(ChatFormatting.GOLD),
            false
        );

        source.sendSuccess(
            () -> Component.translatable("command.tiedup.cell.info_id", cell.getId().toString()).withStyle(ChatFormatting.GRAY),
            false
        );

        source.sendSuccess(
            () -> Component.translatable("command.tiedup.cell.info_state", cell.getState().toString()).withStyle(ChatFormatting.GRAY),
            false
        );

        source.sendSuccess(
            () ->
                Component.translatable(
                    "command.tiedup.cell.info_core_pos", cell.getCorePos().toShortString()
                ).withStyle(ChatFormatting.GRAY),
            false
        );

        // Spawn point (may be null in V2)
        if (cell.getSpawnPoint() != null) {
            source.sendSuccess(
                () ->
                    Component.translatable(
                        "command.tiedup.cell.info_spawn_point", cell.getSpawnPoint().toShortString()
                    ).withStyle(ChatFormatting.GRAY),
                false
            );
        }

        // Owner info
        if (cell.hasOwner()) {
            ServerPlayer owner = level
                .getServer()
                .getPlayerList()
                .getPlayer(cell.getOwnerId());
            String ownerName =
                owner != null ? owner.getName().getString() : "(offline)";
            source.sendSuccess(
                () ->
                    Component.translatable(
                        "command.tiedup.cell.info_owner",
                        ownerName,
                        cell.getOwnerId().toString().substring(0, 8) + "..."
                    ).withStyle(ChatFormatting.GRAY),
                false
            );
        } else {
            source.sendSuccess(
                () -> Component.translatable("command.tiedup.cell.info_owner_world").withStyle(ChatFormatting.GRAY),
                false
            );
        }

        // Geometry
        source.sendSuccess(
            () ->
                Component.translatable(
                    "command.tiedup.cell.info_interior", cell.getInteriorBlocks().size()
                ).withStyle(ChatFormatting.GRAY),
            false
        );
        source.sendSuccess(
            () ->
                Component.translatable(
                    "command.tiedup.cell.info_walls", cell.getWallBlocks().size()
                ).withStyle(ChatFormatting.GRAY),
            false
        );

        // Breach info
        if (!cell.getBreachedPositions().isEmpty()) {
            source.sendSuccess(
                () ->
                    Component.translatable(
                        "command.tiedup.cell.info_breaches",
                        cell.getBreachedPositions().size(),
                        String.format("%.1f", cell.getBreachPercentage() * 100)
                    ).withStyle(ChatFormatting.RED),
                false
            );
        }

        // Features
        if (!cell.getBeds().isEmpty()) {
            source.sendSuccess(
                () -> Component.translatable("command.tiedup.cell.info_beds", cell.getBeds().size()).withStyle(ChatFormatting.GRAY),
                false
            );
        }
        if (!cell.getAnchors().isEmpty()) {
            source.sendSuccess(
                () -> Component.translatable("command.tiedup.cell.info_anchors", cell.getAnchors().size()).withStyle(ChatFormatting.GRAY),
                false
            );
        }
        if (!cell.getDoors().isEmpty()) {
            source.sendSuccess(
                () -> Component.translatable("command.tiedup.cell.info_doors", cell.getDoors().size()).withStyle(ChatFormatting.GRAY),
                false
            );
        }

        // Prisoners
        source.sendSuccess(
            () ->
                Component.translatable(
                    "command.tiedup.cell.info_prisoners", cell.getPrisonerCount()
                ).withStyle(ChatFormatting.GRAY),
            false
        );
        for (UUID prisonerId : cell.getPrisonerIds()) {
            ServerPlayer prisoner = level
                .getServer()
                .getPlayerList()
                .getPlayer(prisonerId);
            String prisonerName =
                prisoner != null ? prisoner.getName().getString() : "(offline)";
            source.sendSuccess(
                () -> Component.literal("  - " + prisonerName).withStyle(ChatFormatting.GRAY),
                false
            );
        }
    }
}
