// Structure Breaking System
import { world, system, ItemStack } from '@minecraft/server';
import { 
  structureItems, 
  getExclusiveStructureBlocks, 
  getStructureFamilies,
  isExclusiveStructureBlock,
  getStructureFamilyForBlock
} from './config.js';
import { debug } from './utils.js';



/**
 * Register block break event handler
 */
export function registerBlockBreakEvents() {
  world.beforeEvents.playerBreakBlock.subscribe(handleBlockBreak);
  debug('info', 'Structure breaking events registered');
}

/**
 * Handle block break events to detect structure block breaking
 * @param {PlayerBreakBlockBeforeEvent} event - The block break event
 */
function handleBlockBreak(event) {
  const block = event.block;
  const player = event.player;
  const blockType = block.typeId;
  
  // Check if this block is an exclusive structure block
  if (isExclusiveStructureBlock(blockType)) {
    debug('info', `Exclusive structure block broken: ${blockType}`);
    
    // Cancel the normal block break
    event.cancel = true;
    
    // Break the entire structure in the next tick
    system.run(() => {
      breakEntireStructure(block.location, player);
    });
  }
}

/**
 * Break an entire structure by scanning vertically from the broken block
 * @param {Vector3} startLocation - The location where the block was broken
 * @param {Player} player - The player who broke the block
 */
function breakEntireStructure(startLocation, player) {
  debug('info', `Breaking entire structure at ${startLocation.x}, ${startLocation.y}, ${startLocation.z}`);
  
  // Find all connected structure blocks
  const blocksToBreak = findConnectedStructureBlocks(startLocation, player.dimension);
  
  if (blocksToBreak.length === 0) {
    debug('warn', 'No connected structure blocks found');
    return;
  }
  
  debug('info', `Found ${blocksToBreak.length} connected structure blocks`);
  
  // Determine the structure type by analyzing the found blocks
  const structureType = detectStructureType(blocksToBreak, player.dimension);
  
  if (!structureType) {
    debug('error', 'Could not determine structure type');
    player.onScreenDisplay.setActionBar('§cCould not identify structure type.');
    return;
  }
  
  debug('info', `Detected structure type: ${structureType}`);
  
  // Break all the blocks
  const dimension = player.dimension;
  let brokenCount = 0;
  
  for (const location of blocksToBreak) {
    const block = dimension.getBlock(location);
    if (block && isExclusiveStructureBlock(block.typeId)) {
      block.setType('minecraft:air');
      brokenCount++;
    }
  }
  
  debug('info', `Successfully broke ${brokenCount} structure blocks`);

  player.playSound('block.lantern.break');
  
  // Spawn the structure item
  spawnStructureItem(startLocation, structureType, player);
}

/**
 * Find all connected structure blocks using recursive flood-fill algorithm
 * @param {Vector3} startLocation - The starting location
 * @param {Dimension} dimension - The dimension to scan in
 * @returns {Vector3[]} Array of locations of connected structure blocks
 */
function findConnectedStructureBlocks(startLocation, dimension) {
  const blocksToBreak = [];
  const visited = new Set();
  const toVisit = [startLocation];
  
  // Helper function to create location key
  const locationKey = (loc) => `${loc.x},${loc.y},${loc.z}`;
  
  // All 6 directions: up, down, north, south, east, west
  const directions = [
    { x: 0, y: 1, z: 0 },   // Up
    { x: 0, y: -1, z: 0 },  // Down
    { x: 0, y: 0, z: -1 },  // North
    { x: 0, y: 0, z: 1 },   // South
    { x: 1, y: 0, z: 0 },   // East
    { x: -1, y: 0, z: 0 }   // West
  ];
  
  debug('info', `Starting flood-fill from ${startLocation.x},${startLocation.y},${startLocation.z}`);
  
  // Flood-fill algorithm to find all connected structure blocks
  while (toVisit.length > 0) {
    const currentLocation = toVisit.pop();
    const key = locationKey(currentLocation);
    
    // Skip if already visited
    if (visited.has(key)) {
      continue;
    }
    
    // Check if current location has a structure block
    const currentBlock = dimension.getBlock(currentLocation);
    if (!currentBlock || !isExclusiveStructureBlock(currentBlock.typeId)) {
      continue;
    }
    
    // Mark as visited and add to results
    visited.add(key);
    blocksToBreak.push(currentLocation);
    debug('info', `Found connected block: ${currentBlock.typeId} at ${currentLocation.x},${currentLocation.y},${currentLocation.z}`);
    
    // Check all 6 adjacent positions
    for (const dir of directions) {
      const nextLocation = {
        x: currentLocation.x + dir.x,
        y: currentLocation.y + dir.y,
        z: currentLocation.z + dir.z
      };
      
      const nextKey = locationKey(nextLocation);
      
      // Add to visit queue if not already visited
      if (!visited.has(nextKey)) {
        toVisit.push(nextLocation);
      }
    }
  }
  
  debug('info', `Flood-fill found ${blocksToBreak.length} connected structure blocks`);
  return blocksToBreak;
}



/**
 * Detect the specific structure type by analyzing the blocks found
 * @param {Vector3[]} blockLocations - Array of block locations in the structure
 * @param {Dimension} dimension - The dimension to check blocks in
 * @returns {string|null} The detected structure type or null if unknown
 */
function detectStructureType(blockLocations, dimension) {
  // Count occurrences of each block type
  const blockCounts = {};
  const blockTypes = new Set();
  
  for (const location of blockLocations) {
    const block = dimension.getBlock(location);
    if (block && isExclusiveStructureBlock(block.typeId)) {
      blockTypes.add(block.typeId);
      blockCounts[block.typeId] = (blockCounts[block.typeId] || 0) + 1;
    }
  }
  
  debug('info', `Block analysis: ${JSON.stringify(blockCounts)}`);
  
  // Determine structure family first
  let structureFamily = null;
  const structureFamilies = getStructureFamilies();
  for (const [family, config] of Object.entries(structureFamilies)) {
    const familyBlocks = new Set(config.blocks);
    const hasAnyFamilyBlock = [...blockTypes].some(blockType => familyBlocks.has(blockType));
    
    if (hasAnyFamilyBlock) {
      structureFamily = family;
      break;
    }
  }
  
  if (!structureFamily) {
    debug('error', 'Could not determine structure family');
    return null;
  }
  
  debug('info', `Detected structure family: ${structureFamily}`);
  
  // Apply family-specific detection logic
  switch (structureFamily) {
    case 'street_light':
      return detectStreetLightType(blockCounts, blockTypes);
    
    case 'utility_pole':
      return detectUtilityPoleType(blockCounts, blockTypes);
    
    default:
      debug('error', `Unknown structure family: ${structureFamily}`);
      return null;
  }
}

/**
 * Detect specific street light type (single vs double)
 * @param {Object} blockCounts - Count of each block type
 * @param {Set} blockTypes - Set of block types present
 * @returns {string} The detected street light type
 */
function detectStreetLightType(blockCounts, blockTypes) {
  const lightCount = blockCounts['dss_st:dss_st_street_light_light'] || 0;
  const armCount = blockCounts['dss_st:dss_st_street_light_arm'] || 0;
  
  // Double street light has 2 lights and typically 2+ arms
  if (lightCount >= 2) {
    debug('info', `Detected double street light: ${lightCount} lights, ${armCount} arms`);
    return 'double-street-light';
  } else {
    debug('info', `Detected single street light: ${lightCount} lights, ${armCount} arms`);
    return 'single-street-light';
  }
}

/**
 * Detect specific utility pole type (with or without transformer, line vs junction)
 * @param {Object} blockCounts - Count of each block type
 * @param {Set} blockTypes - Set of block types present
 * @returns {string} The detected utility pole type
 */
function detectUtilityPoleType(blockCounts, blockTypes) {
  const hasTransformer = blockTypes.has('dss_st:dss_st_transformer');
  const hasJunctionTop = blockTypes.has('dss_st:dss_st_util_pole_top_junc');
  const hasJunctionArms = blockTypes.has('dss_st:util_pole_arm_junc_top') || blockTypes.has('dss_st:util_pole_arm_junc_bot');
  
  // Determine if it's a junction pole (has junction-specific blocks)
  const isJunction = hasJunctionTop || hasJunctionArms;
  
  if (hasTransformer) {
    debug('info', `Detected utility pole with transformer (junction: ${isJunction})`);
    return 'util-pole-trans';
  } else {
    debug('info', `Detected utility pole without transformer (junction: ${isJunction})`);
    return 'util-pole';
  }
}

/**
 * Spawn the structure item at the break location
 * @param {Vector3} location - The location to spawn the item
 * @param {string} structureType - The type of structure that was broken
 * @param {Player} player - The player who broke the structure
 */
function spawnStructureItem(location, structureType, player) {
    const structureConfig = structureItems[structureType];

    const dm = player.dimension;

    if (!structureConfig) {
      debug('error', `Unknown structure type: ${structureType}`);
      return;
    }
    
    const itemId = structureConfig.item;
    const displayName = structureConfig.display_name;
  
    const spawnLocation = {
      x: location.x + 0.5,
      y: location.y + 1,
      z: location.z + 0.5
    };
    
    dm.spawnItem(new ItemStack(itemId), spawnLocation);
    
    // Notify the player
    player.onScreenDisplay.setActionBar(`§aStructure broken! Dropped: ${displayName}`);
    debug('info', `Spawned structure item: ${itemId} at ${spawnLocation.x}, ${spawnLocation.y}, ${spawnLocation.z}`);
}


