// Validation functions for Structure Building System
// Handles placement validation, space checking, and permission verification

import { world } from '@minecraft/server';
import { debug } from './utils.js';
import { structureTemplates, validateStructureSpacing } from './config.js';
import { calculateStructureDimensions } from './utils.js';

/**
 * Validate structure placement at the specified location
 * @param {Vector3} location - The placement location
 * @param {string} face - The block face that was clicked
 * @param {Object} structureItem - The structure item configuration
 * @returns {Object} Validation result with valid flag and reason
 */
export function validateStructurePlacement(location, face, structureItem, player) {
    // Check if location is valid
    if (!isValidLocation(location, player)) {
      return { valid: false, reason: 'Invalid placement location' };
    }
    
    // Check if face is appropriate for structure placement
    if (!isValidFace(face, structureItem)) {
      return { valid: false, reason: 'Cannot place structure on this surface' };
    }
    
    // Check if there's enough space between structures (NEW!)
    const templateKey = structureItem.structure_templates[0]; // Use first template for spacing check
    const spacingResult = validateStructureSpacing(templateKey, location, player.dimension);
    if (!spacingResult.valid) {
      debug('info', `Spacing validation failed: ${spacingResult.reason}`);
      return spacingResult;
    }
    
    // Check if there's enough space for the structure
    const spaceResult = validateSpaceRequirements(location, face, structureItem);
    if (!spaceResult.valid) {
      return spaceResult;
    }
    
    // Check for conflicting blocks
    const conflictResult = validateNoConflicts(location, face, structureItem, player);
    if (!conflictResult.valid) {
      return conflictResult;
    }
    
    return { valid: true, reason: 'Placement validated successfully' };
}

/**
 * Check if the location coordinates are valid
 * @param {Vector3} location - The location to check
 * @returns {boolean} True if location is valid
 */
function isValidLocation(location, player) {
  debug('info', `Validating location: ${JSON.stringify(location)}`);
  const placeLocation = {x: location.x, y: location.y + 1, z: location.z}
  return location && 
         typeof location.x === 'number' && 
         typeof location.y === 'number' && 
         player.dimension.getBlock(placeLocation).typeId === 'minecraft:air' &&
         typeof location.z === 'number' &&
         location.y >= -64 && location.y <= 320; // Standard world height limits
}

/**
 * Check if the clicked face is appropriate for structure placement
 * @param {string} face - The block face
 * @param {Object} structureItem - The structure item configuration
 * @returns {boolean} True if face is valid
 */
function isValidFace(face, structureItem) {
  // Most structures should be placed on top surfaces
  const validFaces = ['Up'];

  debug('info', `Validating face: ${face}`);
  
  // Some structures might allow side placement
  if (structureItem.key && structureItem.key.includes('wall')) {
    validFaces.push('North', 'South', 'East', 'West');
  }

  debug('info', `Valid faces: ${validFaces}`);
  
  return validFaces.includes(face);
}

/**
 * Validate space requirements for structure placement
 * @param {Vector3} location - The placement location
 * @param {string} face - The block face
 * @param {Object} structureItem - The structure item configuration
 * @returns {Object} Validation result
 */
function validateSpaceRequirements(location, face, structureItem) {
    // Get the first template to estimate space requirements
    const templateKey = structureItem.structure_templates[0];
    const template = structureTemplates[templateKey];
    
    if (!template) {
      return { valid: false, reason: 'Template not found for space validation' };
    }
    
    // Calculate approximate structure bounds
    const bounds = calculateStructureBounds(template, location, face);
    
    // Check if structure fits within world bounds
    if (bounds.maxY > 320 || bounds.minY < -64) {
      return { valid: false, reason: 'Structure would exceed world height limits' };
    }
    
    // Check horizontal space (basic check)
    const horizontalSize = Math.max(bounds.maxX - bounds.minX, bounds.maxZ - bounds.minZ);
    if (horizontalSize > 50) { // Arbitrary large structure limit
      return { valid: false, reason: 'Structure is too large for this location' };
    }
    
    return { valid: true, reason: 'Space requirements met' };
}

/**
 * Calculate approximate bounds for a structure
 * @param {Object} template - The structure template
 * @param {Vector3} location - The base location
 * @param {string} face - The block face
 * @returns {Object} Bounds object with min/max coordinates
 */
function calculateStructureBounds(template, location, face) {
  let minX = location.x, maxX = location.x;
  let minY = location.y, maxY = location.y;
  let minZ = location.z, maxZ = location.z;
  
  // Estimate bounds based on template parts
  for (const part of template.parts) {
    if (part.repeat) {
      const maxCount = typeof part.repeat.max === 'number' ? part.repeat.max : 10;
      const direction = part.repeat.direction;
      
      switch (direction) {
        case 'up':
        case 'vertical':
          maxY += maxCount;
          break;
        case 'down':
          minY -= maxCount;
          break;
        case 'north':
          minZ -= maxCount;
          break;
        case 'south':
          maxZ += maxCount;
          break;
        case 'east':
          maxX += maxCount;
          break;
        case 'west':
          minX -= maxCount;
          break;
        case 'horizontal':
          maxX += maxCount;
          maxZ += maxCount;
          break;
      }
    }
  }
  
  return { minX, maxX, minY, maxY, minZ, maxZ };
}

/**
 * Validate if there's enough empty space for the structure with selected dimensions
 * @param {Object} structureItem - The structure item configuration
 * @param {string} templateKey - The template key to use
 * @param {Vector3} location - The build location
 * @param {string} face - The block face that was clicked
 * @param {Player} player - The player building the structure
 * @param {Object} selectedDimensions - Selected dimensions from UI sliders
 * @returns {Object} Validation result with success status and error message
 */
export function validateStructureSpace(structureItem, templateKey, location, face, player, selectedDimensions = null) {
  const template = structureTemplates[templateKey];
  if (!template) {
    return { valid: false, reason: 'Template not found for space validation' };
  }
  
  // Validate spacing between structures first
  const spacingResult = validateStructureSpacing(templateKey, location, player.dimension);
  if (!spacingResult.valid) {
    debug('info', `Structure space validation failed due to spacing: ${spacingResult.reason}`);
    return spacingResult;
  }
  
  // Calculate structure dimensions based on selected dimensions
  const dimensions = calculateStructureDimensions(template);
  
  // Use selected dimensions or default to minimum
  const actualHeight = selectedDimensions?.height || dimensions.height.min;
  const actualWidth = selectedDimensions?.width || dimensions.width.min;
  const actualDepth = selectedDimensions?.depth || dimensions.depth.min;
  
  debug('info', `Validating space for structure: ${actualWidth}x${actualHeight}x${actualDepth}`);
  
  // Calculate base position based on clicked face
  const baseLocation = calculateBaseLocation(location, face);
  
  // Define the area to check based on structure dimensions and player facing
  const checkBounds = calculateStructureCheckBounds(baseLocation, actualWidth, actualHeight, actualDepth, player);
  
  // Check if all positions in the structure area are empty or replaceable
  const emptySpaceCheck = checkEmptySpace(player.dimension, checkBounds);
  
  if (!emptySpaceCheck.valid) {
    return { 
      valid: false, 
      reason: 'Can\'t place structure here.',
      details: emptySpaceCheck.reason 
    };
  }
  
  return { valid: true, reason: 'Space is available for structure placement' };
}

/**
 * Calculate the bounds to check for empty space based on structure dimensions
 * @param {Vector3} baseLocation - The base build location
 * @param {number} width - Structure width
 * @param {number} height - Structure height
 * @param {number} depth - Structure depth
 * @param {Player} player - The player (for facing direction)
 * @returns {Object} Bounds object with min/max coordinates
 */
function calculateStructureCheckBounds(baseLocation, width, height, depth, player) {
  // Start with base location
  let minX = baseLocation.x;
  let maxX = baseLocation.x;
  let minY = baseLocation.y;
  let maxY = baseLocation.y + height - 1; // Height extends upward
  let minZ = baseLocation.z;
  let maxZ = baseLocation.z;
  
  // Expand bounds based on width and depth
  // For now, assume structure extends symmetrically from center
  const halfWidth = Math.floor(width / 2);
  const halfDepth = Math.floor(depth / 2);
  
  minX -= halfWidth;
  maxX += halfWidth;
  minZ -= halfDepth;
  maxZ += halfDepth;
  
  debug('info', `Structure check bounds: X(${minX}-${maxX}), Y(${minY}-${maxY}), Z(${minZ}-${maxZ})`);
  
  return { minX, maxX, minY, maxY, minZ, maxZ };
}

/**
 * Check if the specified area is empty or contains only replaceable blocks
 * @param {Dimension} dimension - The dimension to check
 * @param {Object} bounds - The bounds to check
 * @returns {Object} Check result with valid status and reason
 */
function checkEmptySpace(dimension, bounds) {
  const blocksToCheck = [];
  
  // Collect all positions to check
  for (let x = bounds.minX; x <= bounds.maxX; x++) {
    for (let y = bounds.minY; y <= bounds.maxY; y++) {
      for (let z = bounds.minZ; z <= bounds.maxZ; z++) {
        blocksToCheck.push({ x, y, z });
      }
    }
  }
  
  debug('info', `Checking ${blocksToCheck.length} positions for empty space`);
  
  // Check each position
  let solidBlocks = 0;
  let checkedBlocks = 0;
  
  for (const pos of blocksToCheck) {
    const block = dimension.getBlock(pos);
    if (block) {
      checkedBlocks++;
      
      // Check if block is solid (not air, water, or other replaceable blocks)
      if (!isReplaceableBlock(block.typeId)) {
        solidBlocks++;
        
        // If too many solid blocks, fail early
        if (solidBlocks > Math.floor(blocksToCheck.length * 0.3)) { // Allow up to 30% solid blocks
          debug('info', `Too many solid blocks found: ${solidBlocks}/${checkedBlocks}`);
          return { 
            valid: false, 
            reason: `Area contains ${solidBlocks} solid blocks that would interfere with structure placement` 
          };
        }
      }
    }
  }
  
  debug('info', `Space check complete: ${solidBlocks}/${checkedBlocks} solid blocks found`);
  
  return { valid: true, reason: `Area is suitable for structure placement (${solidBlocks} solid blocks found)` };
}

/**
 * Check if a block type is replaceable (can be built over)
 * @param {string} blockTypeId - The block type ID
 * @returns {boolean} True if the block is replaceable
 */
function isReplaceableBlock(blockTypeId) {
  const replaceableBlocks = [
    'minecraft:air',
    'minecraft:water',
    'minecraft:flowing_water',
    'minecraft:lava',
    'minecraft:flowing_lava',
    'minecraft:grass',
    'minecraft:tall_grass',
    'minecraft:fern',
    'minecraft:large_fern',
    'minecraft:dead_bush',
    'minecraft:vine',
    'minecraft:snow_layer',
    'minecraft:fire'
  ];
  
  return replaceableBlocks.includes(blockTypeId);
}

/**
 * Calculate base position based on clicked face (helper function)
 * @param {Vector3} location - The clicked location
 * @param {string} face - The block face that was clicked
 * @returns {Vector3} The base build location
 */
function calculateBaseLocation(location, face) {
  // For now, assume structures are built on top of the clicked block
  return {
    x: location.x,
    y: location.y + 1,
    z: location.z
  };
}

/**
 * Validate that structure placement won't conflict with existing blocks
 * @param {Vector3} location - The placement location
 * @param {string} face - The block face
 * @param {Object} structureItem - The structure item configuration
 * @returns {Object} Validation result
 */
function validateNoConflicts(location, face, structureItem, player = null) {
    // For now, implement basic conflict checking
    // In a full implementation, you'd check all positions the structure will occupy
    
    const dimension = world.getDimension('overworld');
    const baseBlock = dimension.getBlock(location);
    
    if (!baseBlock) {
      return { valid: false, reason: 'Cannot access placement location' };
    }
    
    // Check if base block is solid (for structures that need ground support)
    if (face === 'Up' && !isSolidBlock(baseBlock.typeId)) {
      return { valid: false, reason: 'Structure requires solid ground for placement' };
    }
    
    // Check a few blocks above for basic clearance
    for (let i = 1; i <= 12; i++) {
      const checkLocation = {
        x: location.x,
        y: location.y + i,
        z: location.z
      };
      
      const checkBlock = dimension.getBlock(checkLocation);
      if (checkBlock && !isReplaceable(checkBlock.typeId)) {
        return { valid: false, reason: 'Not enough clearance above placement location' };
      }
    }

    // Improved side clearance check for structures with horizontal components
    if (structureItem.display_name.includes('Light')) {
      const sideCheck = validateSideClearance(location, player, dimension, 3);
      if (!sideCheck.valid) {
        return sideCheck;
      }
    } else {
      const sideCheck = validateSideClearance(location, player, dimension, 1);
      if (!sideCheck.valid) {
        return sideCheck;
      }
    }
    
    return { valid: true, reason: 'No conflicts detected' };
}

/**
 * Validate side clearance for structures with horizontal components
 * @param {Vector3} location - The base location
 * @param {Player} player - The player (for facing direction)
 * @param {Dimension} dimension - The dimension to check
 * @param {number} clearanceDistance - How far to check in each direction
 * @returns {Object} Validation result
 */
function validateSideClearance(location, player, dimension, clearanceDistance = 3) {
  if (!player) {
    // Fallback to basic check if no player context
    return validateBasicSideClearance(location, dimension, clearanceDistance);
  }
  
  // Get player facing direction
  const yaw = player.getRotation().y;
  const playerFacing = getCardinalFromYaw(yaw);
  
  // Define relative directions based on player facing
  const directions = getPlayerRelativeDirections(playerFacing);
  
  // Check left and right sides relative to player facing
  const sidesToCheck = ['left', 'right'];
  
  for (const side of sidesToCheck) {
    const direction = directions[side];
    
    for (let i = 1; i <= clearanceDistance; i++) {
      // Check from y+4 to y+13 (where street light arms are typically placed)
      for (let yOffset = 4; yOffset <= 13; yOffset++) {
        const checkLocation = {
          x: location.x + (direction.x * i),
          y: location.y + yOffset,
          z: location.z + (direction.z * i)
        };
        
        const checkBlock = dimension.getBlock(checkLocation);
        if (checkBlock && !isReplaceable(checkBlock.typeId)) {
          debug('info', `Side clearance blocked at ${side} ${i} blocks, height ${yOffset}: ${checkBlock.typeId}`);
          return { 
            valid: false, 
            reason: `Not enough clearance on the ${side} side` 
          };
        }
      }
    }
  }
  
  return { valid: true, reason: 'Side clearance validated' };
}

/**
 * Get player-relative directions based on cardinal facing
 * @param {string} playerFacing - Cardinal direction (north, east, south, west)
 * @returns {Object} Object with left, right, forward, backward direction vectors
 */
function getPlayerRelativeDirections(playerFacing) {
  const directionMaps = {
    'north': {
      left: { x: 1, z: 0 },    // East (swapped for validation)
      right: { x: -1, z: 0 },  // West (swapped for validation)
      forward: { x: 0, z: -1 }, // North
      backward: { x: 0, z: 1 }  // South
    },
    'east': {
      left: { x: 0, z: 1 },    // South (swapped for validation)
      right: { x: 0, z: -1 },  // North (swapped for validation)
      forward: { x: 1, z: 0 },  // East
      backward: { x: -1, z: 0 } // West
    },
    'south': {
      left: { x: -1, z: 0 },   // West (swapped for validation)
      right: { x: 1, z: 0 },   // East (swapped for validation)
      forward: { x: 0, z: 1 },  // South
      backward: { x: 0, z: -1 } // North
    },
    'west': {
      left: { x: 0, z: -1 },   // North (swapped for validation)
      right: { x: 0, z: 1 },   // South (swapped for validation)
      forward: { x: -1, z: 0 }, // West
      backward: { x: 1, z: 0 }  // East
    }
  };
  
  return directionMaps[playerFacing] || directionMaps['north'];
}

/**
 * Convert player yaw to cardinal direction
 * @param {number} yaw - Player yaw rotation
 * @returns {string} Cardinal direction
 */
function getCardinalFromYaw(yaw) {
  // Normalize yaw to 0-360 range
  let normalizedYaw = ((yaw % 360) + 360) % 360;
  
  if (normalizedYaw >= 315 || normalizedYaw < 45) {
    return 'north';
  } else if (normalizedYaw >= 45 && normalizedYaw < 135) {
    return 'east';
  } else if (normalizedYaw >= 135 && normalizedYaw < 225) {
    return 'south';
  } else {
    return 'west';
  }
}

/**
 * Fallback side clearance check when no player context is available
 * @param {Vector3} location - The base location
 * @param {Dimension} dimension - The dimension to check
 * @param {number} clearanceDistance - How far to check in each direction
 * @returns {Object} Validation result
 */
function validateBasicSideClearance(location, dimension, clearanceDistance) {
  // Check all four cardinal directions when no player context
  const directions = [
    { name: 'east', x: 1, z: 0 },
    { name: 'west', x: -1, z: 0 },
    { name: 'north', x: 0, z: -1 },
    { name: 'south', x: 0, z: 1 }
  ];
  
  for (const dir of directions) {
    for (let i = 1; i <= clearanceDistance+2; i++) {
      const checkLocation = {
        x: location.x + (dir.x * i),
        y: location.y,
        z: location.z + (dir.z * i)
      };
      const checkBlock = dimension.getBlock(checkLocation);
      if (checkBlock && !isReplaceable(checkBlock.typeId)) {
        return { 
          valid: false, 
          reason: `Not enough clearance on the ${dir.name} side of placement location` 
        };
      }
    }
  }
  
  return { valid: true, reason: 'Basic side clearance validated' };
}

/**
 * Check if a block type is considered solid for structure support
 * @param {string} blockTypeId - The block type identifier
 * @returns {boolean} True if block is solid
 */
function isSolidBlock(blockTypeId) {
  // Handle obvious non-solid blocks first
  const nonSolidPattern = /slab|stair|trapdoor|fence|wall|scaffolding|ice|bars|carpet|torch|redstone|barrel|chest|door|gate|button|pressure_plate|lever|rail|glass_pane|chain|lantern|campfire|sapling|flower|mushroom|vine|ladder|sign|banner|head|skull|air|water|lava/i;
  
  if (nonSolidPattern.test(blockTypeId)) {
    return false;
  }
  
  // Handle special cases that might not follow the pattern
  const definitelyNonSolid = new Set([
    'minecraft:soul_sand',
    'minecraft:honey_block',
    'minecraft:slime_block',
    'minecraft:cobweb'
  ]);
  
  return !definitelyNonSolid.has(blockTypeId);
}

/**
 * Check if a block can be replaced during structure placement
 * @param {string} blockTypeId - The block type identifier
 * @returns {boolean} True if block can be replaced
 */
function isReplaceable(blockTypeId) {
  const replaceableBlocks = [
    'minecraft:air',
    'minecraft:water',
    'minecraft:lava',
    'minecraft:grass',
    'minecraft:tall_grass',
    'minecraft:fern',
    'minecraft:dead_bush',
    'minecraft:vine',
    'minecraft:snow_layer'
  ];
  
  return replaceableBlocks.includes(blockTypeId);
}

/**
 * Validate player permissions for structure building
 * @param {Player} player - The player to check
 * @param {Vector3} location - The build location
 * @returns {Object} Validation result
 */
export function validatePlayerPermissions(player, location) {
    // Check basic build permissions
    if (!player.hasTag('structure_builder') && 
        player.getGameMode() !== 'creative' && 
        !player.isOp()) {
      return { valid: false, reason: 'You need structure builder permissions' };
    }
    
    // Check if location is in a protected area (basic implementation)
    if (isProtectedArea(location)) {
      return { valid: false, reason: 'Cannot build structures in protected areas' };
    }
    
    return { valid: true, reason: 'Player has required permissions' };
}

/**
 * Check if a location is in a protected area
 * @param {Vector3} location - The location to check
 * @returns {boolean} True if location is protected
 */
function isProtectedArea(location) {
  // Basic implementation - can be extended with region protection systems
  // For now, protect spawn area (example)
  const spawnProtectionRadius = 100;
  const distance = Math.sqrt(location.x * location.x + location.z * location.z);
  
  return distance < spawnProtectionRadius;
}

/**
 * Validate structure template integrity
 * @param {Object} template - The structure template to validate
 * @returns {Object} Validation result
 */
export function validateTemplate(template) {
    if (!template || !template.parts || !Array.isArray(template.parts)) {
      return { valid: false, reason: 'Invalid template structure' };
    }
    
    if (template.parts.length === 0) {
      return { valid: false, reason: 'Template has no parts defined' };
    }
    
    // Validate each part
    for (let i = 0; i < template.parts.length; i++) {
      const part = template.parts[i];
      const partResult = validateTemplatePart(part, i);
      if (!partResult.valid) {
        return { valid: false, reason: `Part ${i}: ${partResult.reason}` };
      }
    }
    
    return { valid: true, reason: 'Template is valid' };
}

/**
 * Validate a single template part
 * @param {Object} part - The part to validate
 * @param {number} index - The part index for error reporting
 * @returns {Object} Validation result
 */
function validateTemplatePart(part, index) {
  if (!part.name || typeof part.name !== 'string') {
    return { valid: false, reason: 'Part name is required and must be a string' };
  }
  
  if (!part.block || typeof part.block !== 'string') {
    return { valid: false, reason: 'Part block is required and must be a string' };
  }
  
  if (!part.placement || typeof part.placement !== 'object') {
    return { valid: false, reason: 'Part placement configuration is required' };
  }
  
  if (!part.placement.type || typeof part.placement.type !== 'string') {
    return { valid: false, reason: 'Part placement type is required' };
  }
  
  const validPlacementTypes = [
    'on_ground', 'on_previous', 'on_top', 
    'attach_left', 'attach_right', 'attach_front', 'attach_back',
    'on_floor', 'at_layer', 'relative_to_part'
  ];
  
  if (!validPlacementTypes.includes(part.placement.type)) {
    return { valid: false, reason: `Invalid placement type: ${part.placement.type}` };
  }
  
  return { valid: true, reason: 'Part is valid' };
}