/**
 * Smart Reflow Engine
 * 
 * Enables content blocks authored for one container size to dynamically adapt
 * when placed in containers with different dimensions or aspect ratios.
 * 
 * Unlike simple scaling, reflow REPOSITIONS and RESIZES individual layers
 * to optimally use available space while maintaining visual hierarchy.
 * 
 * @module reflow-engine
 * @see /docs/SPEC-SMART-REFLOW.md
 */

// ============================================================================
// CONFIGURATION
// ============================================================================

const REFLOW_CONFIG = {
  fillPercentage: 0.88,      // Use 88% of container (12% total margin)
  minMargin: 16,             // Minimum 16px margin on any side
  
  text: {
    minFontSize: 14,         // Never smaller than 14px
    maxFontSize: 72,         // Never larger than 72px
    scaleWithContainer: true
  },
  
  artwork: {
    minSize: 80,             // Minimum 80px dimension
    maxSize: 600,            // Maximum 600px dimension
    preferSquare: true       // Maintain 1:1 aspect ratio
  },
  
  // Aspect ratio thresholds for layout mode detection
  aspectThresholds: {
    horizontal: 2.0,         // > 2.0 = "horizontal" (e.g., 1280x240 = 5.33)
    vertical: 0.75,          // < 0.75 = "vertical" (e.g., 320x480 = 0.67)
    // 0.75 - 2.0 = "similar" - use proportional scaling
  }
};

// Layer role definitions for auto-detection
const ROLE_KEYWORDS = {
  artwork: ['artwork', 'image', 'poster', 'thumbnail', 'cover', 'logo'],
  'primary-text': ['title', 'name', 'heading', 'artist'],
  'secondary-text': ['subtitle', 'description', 'track', 'message', 'content'],
  decoration: ['background', 'overlay', 'divider', 'border'],
  badge: ['icon', 'badge', 'indicator', 'status']
};

// ============================================================================
// UTILITY FUNCTIONS
// ============================================================================

/**
 * Detect aspect ratio change category between two sizes
 * @param {Object} authored - { width, height } of authored content block
 * @param {Object} target - { width, height } of target container
 * @returns {'horizontal-to-vertical'|'vertical-to-horizontal'|'similar'}
 */
function detectAspectChange(authored, target) {
  const authoredRatio = authored.width / authored.height;
  const targetRatio = target.width / target.height;
  
  // Horizontal (wide) to Vertical (tall) - need to stack
  if (authoredRatio > REFLOW_CONFIG.aspectThresholds.horizontal && 
      targetRatio < 1.5) {
    return 'horizontal-to-vertical';
  }
  
  // Vertical (tall) to Horizontal (wide) - need to spread
  if (authoredRatio < 1.5 && 
      targetRatio > REFLOW_CONFIG.aspectThresholds.horizontal) {
    return 'vertical-to-horizontal';
  }
  
  return 'similar';
}

/**
 * Auto-detect layer role based on layer properties
 * @param {Object} layer - Layer object with kind, id, token, templateText, etc.
 * @returns {string} Detected role: 'artwork'|'primary-text'|'secondary-text'|'decoration'|'badge'
 */
function detectLayerRole(layer) {
  if (!layer) return 'decoration';
  
  const kind = layer.kind || '';
  const id = (layer.id || '').toLowerCase();
  const token = (layer.token || '').toLowerCase();
  const templateText = (layer.templateText || '').toLowerCase();
  
  // Image layers are artwork
  if (kind === 'token-image') {
    return 'artwork';
  }
  
  // Check text layers for role keywords
  if (kind === 'token-text' || kind === 'static-text') {
    const searchStr = `${id} ${token} ${templateText}`;
    
    for (const [role, keywords] of Object.entries(ROLE_KEYWORDS)) {
      if (keywords.some(kw => searchStr.includes(kw))) {
        return role;
      }
    }
    
    // Default: first text layer is primary, subsequent are secondary
    return 'secondary-text';
  }
  
  return 'decoration';
}

/**
 * Get default reflow metadata for a layer based on its properties
 * @param {Object} layer - Layer object
 * @param {number} index - Layer index in array (for stack order)
 * @returns {Object} Default reflow configuration
 */
export function getDefaultReflowMetadata(layer, index = 0) {
  const role = detectLayerRole(layer);
  
  const defaults = {
    role,
    priority: index + 1,
    stackOrder: index + 1,
    anchor: 'top-left',
    aspectRatio: role === 'artwork' ? 'preserve' : 'flexible'
  };
  
  // Add role-specific defaults
  if (role === 'artwork') {
    defaults.minSize = { width: REFLOW_CONFIG.artwork.minSize, height: REFLOW_CONFIG.artwork.minSize };
    defaults.maxSize = { width: REFLOW_CONFIG.artwork.maxSize, height: REFLOW_CONFIG.artwork.maxSize };
  } else if (role === 'primary-text' || role === 'secondary-text') {
    defaults.minFontSize = REFLOW_CONFIG.text.minFontSize;
    defaults.maxFontSize = REFLOW_CONFIG.text.maxFontSize;
  }
  
  return defaults;
}

/**
 * Ensure layer has reflow metadata, adding defaults if missing
 * @param {Object} layer - Layer object
 * @param {number} index - Layer index
 * @returns {Object} Layer with reflow metadata
 */
export function ensureReflowMetadata(layer, index = 0) {
  if (!layer) return layer;
  
  if (!layer.reflow) {
    layer.reflow = getDefaultReflowMetadata(layer, index);
  }
  
  return layer;
}

// ============================================================================
// LAYOUT CALCULATION FUNCTIONS
// ============================================================================

/**
 * Apply proportional scaling to layers (similar aspect ratios)
 * @param {Array} layers - Array of layer objects
 * @param {Object} authored - { width, height } of authored content block
 * @param {Object} target - { width, height } of target container
 * @returns {Array} Layers with transformed positions and sizes
 */
function applyProportionalScale(layers, authored, target) {
  // Calculate scale factor to fit within target while respecting fill percentage
  const scaleX = (target.width * REFLOW_CONFIG.fillPercentage) / authored.width;
  const scaleY = (target.height * REFLOW_CONFIG.fillPercentage) / authored.height;
  const scale = Math.min(scaleX, scaleY);
  
  // Calculate offset to center the scaled content
  const scaledWidth = authored.width * scale;
  const scaledHeight = authored.height * scale;
  const offsetX = (target.width - scaledWidth) / 2;
  const offsetY = (target.height - scaledHeight) / 2;
  
  return layers.map(layer => {
    if (!layer) return layer;
    
    const reflow = layer.reflow || getDefaultReflowMetadata(layer, 0);
    
    // Scale position and size
    const newX = Math.round((layer.x || 0) * scale + offsetX);
    const newY = Math.round((layer.y || 0) * scale + offsetY);
    const newWidth = Math.round((layer.width || 100) * scale);
    const newHeight = Math.round((layer.height || 100) * scale);
    
    // Apply min/max constraints
    const result = {
      ...layer,
      _reflow: {
        x: newX,
        y: newY,
        width: constrainSize(newWidth, reflow.minSize?.width, reflow.maxSize?.width),
        height: constrainSize(newHeight, reflow.minSize?.height, reflow.maxSize?.height)
      }
    };
    
    // Scale font size for text layers
    if ((layer.kind === 'token-text' || layer.kind === 'static-text') && layer.style?.font_size) {
      const scaledFontSize = Math.round(layer.style.font_size * scale);
      result._reflow.fontSize = constrainSize(
        scaledFontSize,
        reflow.minFontSize || REFLOW_CONFIG.text.minFontSize,
        reflow.maxFontSize || REFLOW_CONFIG.text.maxFontSize
      );
    }
    
    return result;
  });
}

/**
 * Apply vertical stacking layout (horizontal → vertical transition)
 * @param {Array} layers - Array of layer objects
 * @param {Object} target - { width, height } of target container
 * @returns {Array} Layers with transformed positions and sizes
 */
function applyVerticalStack(layers, target) {
  // Sort layers by stack order (artwork first, then text by priority)
  const sortedLayers = [...layers].filter(Boolean).sort((a, b) => {
    const aOrder = a.reflow?.stackOrder ?? 999;
    const bOrder = b.reflow?.stackOrder ?? 999;
    return aOrder - bOrder;
  });
  
  // Calculate available space with margins
  const margin = REFLOW_CONFIG.minMargin;
  const availableWidth = target.width - (margin * 2);
  const availableHeight = target.height - (margin * 2);
  
  // First pass: calculate heights for each layer type
  const artworkLayers = sortedLayers.filter(l => l.reflow?.role === 'artwork');
  const textLayers = sortedLayers.filter(l => 
    l.reflow?.role === 'primary-text' || l.reflow?.role === 'secondary-text'
  );
  const otherLayers = sortedLayers.filter(l => 
    !artworkLayers.includes(l) && !textLayers.includes(l)
  );
  
  // Artwork takes up to 60% of vertical space in vertical layout
  const maxArtworkHeight = availableHeight * 0.6;
  // Text takes remaining space
  const textSpacing = 8; // Space between text lines
  
  let currentY = margin;
  const results = [];
  
  // Position artwork first (if any)
  for (const layer of artworkLayers) {
    const reflow = layer.reflow || getDefaultReflowMetadata(layer, 0);
    
    // Keep artwork square, fit to available width
    const artSize = Math.min(
      availableWidth,
      maxArtworkHeight,
      reflow.maxSize?.width || REFLOW_CONFIG.artwork.maxSize
    );
    const constrainedSize = constrainSize(
      artSize,
      reflow.minSize?.width || REFLOW_CONFIG.artwork.minSize,
      reflow.maxSize?.width || REFLOW_CONFIG.artwork.maxSize
    );
    
    results.push({
      ...layer,
      _reflow: {
        x: Math.round((target.width - constrainedSize) / 2), // Center horizontally
        y: currentY,
        width: constrainedSize,
        height: constrainedSize
      }
    });
    
    currentY += constrainedSize + margin;
  }
  
  // Position text layers below artwork
  const remainingHeight = target.height - currentY - margin;
  const textHeight = Math.max(24, remainingHeight / Math.max(1, textLayers.length) - textSpacing);
  
  for (const layer of textLayers) {
    const reflow = layer.reflow || getDefaultReflowMetadata(layer, 0);
    
    // Calculate font size based on available height
    const baseFontSize = Math.min(textHeight * 0.8, 48); // 80% of height, max 48px
    const fontSize = constrainSize(
      baseFontSize,
      reflow.minFontSize || REFLOW_CONFIG.text.minFontSize,
      reflow.maxFontSize || REFLOW_CONFIG.text.maxFontSize
    );
    
    results.push({
      ...layer,
      _reflow: {
        x: margin,
        y: currentY,
        width: availableWidth,
        height: Math.round(textHeight),
        fontSize
      }
    });
    
    currentY += textHeight + textSpacing;
  }
  
  // Other layers: hide or position at bottom
  for (const layer of otherLayers) {
    results.push({
      ...layer,
      _reflow: {
        x: 0,
        y: 0,
        width: 0,
        height: 0,
        hidden: true
      }
    });
  }
  
  return results;
}

/**
 * Apply horizontal spread layout (vertical → horizontal transition)
 * @param {Array} layers - Array of layer objects
 * @param {Object} target - { width, height } of target container
 * @returns {Array} Layers with transformed positions and sizes
 */
function applyHorizontalSpread(layers, target) {
  // Sort layers by stack order
  const sortedLayers = [...layers].filter(Boolean).sort((a, b) => {
    const aOrder = a.reflow?.stackOrder ?? 999;
    const bOrder = b.reflow?.stackOrder ?? 999;
    return aOrder - bOrder;
  });
  
  const margin = REFLOW_CONFIG.minMargin;
  const availableWidth = target.width - (margin * 2);
  const availableHeight = target.height - (margin * 2);
  
  // Separate layer types
  const artworkLayers = sortedLayers.filter(l => l.reflow?.role === 'artwork');
  const textLayers = sortedLayers.filter(l => 
    l.reflow?.role === 'primary-text' || l.reflow?.role === 'secondary-text'
  );
  
  // Artwork takes left portion (keep square)
  const artSize = Math.min(availableHeight, availableWidth * 0.3);
  let currentX = margin;
  
  const results = [];
  
  // Position artwork on left
  for (const layer of artworkLayers) {
    const reflow = layer.reflow || getDefaultReflowMetadata(layer, 0);
    const constrainedSize = constrainSize(
      artSize,
      reflow.minSize?.width || REFLOW_CONFIG.artwork.minSize,
      reflow.maxSize?.width || REFLOW_CONFIG.artwork.maxSize
    );
    
    results.push({
      ...layer,
      _reflow: {
        x: currentX,
        y: Math.round((target.height - constrainedSize) / 2), // Center vertically
        width: constrainedSize,
        height: constrainedSize
      }
    });
    
    currentX += constrainedSize + margin;
  }
  
  // Text layers fill remaining width, stack vertically
  const textWidth = availableWidth - (currentX - margin);
  const textSpacing = 4;
  const textAreaHeight = availableHeight;
  const perTextHeight = (textAreaHeight - (textSpacing * (textLayers.length - 1))) / Math.max(1, textLayers.length);
  
  let textY = margin;
  for (const layer of textLayers) {
    const reflow = layer.reflow || getDefaultReflowMetadata(layer, 0);
    
    const fontSize = constrainSize(
      Math.min(perTextHeight * 0.7, 56),
      reflow.minFontSize || REFLOW_CONFIG.text.minFontSize,
      reflow.maxFontSize || REFLOW_CONFIG.text.maxFontSize
    );
    
    results.push({
      ...layer,
      _reflow: {
        x: currentX,
        y: textY,
        width: textWidth,
        height: Math.round(perTextHeight),
        fontSize
      }
    });
    
    textY += perTextHeight + textSpacing;
  }
  
  return results;
}

/**
 * Constrain a size value between min and max
 */
function constrainSize(value, min, max) {
  if (min !== undefined && value < min) return min;
  if (max !== undefined && value > max) return max;
  return value;
}

// ============================================================================
// MAIN REFLOW API
// ============================================================================

/**
 * Calculate reflowed layout for layers
 * 
 * @param {Array} layers - Array of layer objects from visual_config
 * @param {Object} authoredSize - { width, height } size the content block was authored for
 * @param {Object} targetSize - { width, height } of the container it's being rendered in
 * @returns {Array} Layers with _reflow property containing transformed positions/sizes
 * 
 * @example
 * const reflowedLayers = calculateReflowLayout(
 *   block.visual_config.layers,
 *   { width: 1280, height: 240 },  // Lower-third authored size
 *   { width: 640, height: 360 }    // Left-half target container
 * );
 * 
 * // Each layer now has _reflow with { x, y, width, height, fontSize? }
 * reflowedLayers.forEach(layer => {
 *   const { x, y, width, height, fontSize } = layer._reflow;
 *   // Use these for rendering instead of original layer.x, layer.y, etc.
 * });
 */
export function calculateReflowLayout(layers, authoredSize, targetSize) {
  if (!layers || !Array.isArray(layers) || layers.length === 0) {
    return [];
  }
  
  // Validate sizes
  if (!authoredSize?.width || !authoredSize?.height || 
      !targetSize?.width || !targetSize?.height) {
    // Return layers with no reflow (use original positions)
    return layers.map(layer => ({
      ...layer,
      _reflow: {
        x: layer.x || 0,
        y: layer.y || 0,
        width: layer.width || 100,
        height: layer.height || 100
      }
    }));
  }
  
  // Ensure all layers have reflow metadata
  const layersWithMetadata = layers.map((layer, i) => ensureReflowMetadata(layer, i));
  
  // Detect aspect change and apply appropriate layout
  const aspectChange = detectAspectChange(authoredSize, targetSize);
  
  switch (aspectChange) {
    case 'horizontal-to-vertical':
      return applyVerticalStack(layersWithMetadata, targetSize);
    
    case 'vertical-to-horizontal':
      return applyHorizontalSpread(layersWithMetadata, targetSize);
    
    case 'similar':
    default:
      return applyProportionalScale(layersWithMetadata, authoredSize, targetSize);
  }
}

/**
 * Check if reflow is needed (sizes differ significantly)
 * @param {Object} authoredSize - { width, height }
 * @param {Object} targetSize - { width, height }
 * @returns {boolean} True if reflow calculation should be applied
 */
export function needsReflow(authoredSize, targetSize) {
  if (!authoredSize || !targetSize) return false;
  
  // Check if sizes differ by more than 5%
  const widthDiff = Math.abs(authoredSize.width - targetSize.width) / authoredSize.width;
  const heightDiff = Math.abs(authoredSize.height - targetSize.height) / authoredSize.height;
  
  return widthDiff > 0.05 || heightDiff > 0.05;
}

/**
 * Get the layout mode that will be used for given sizes
 * @param {Object} authoredSize - { width, height }
 * @param {Object} targetSize - { width, height }
 * @returns {'proportional'|'vertical-stack'|'horizontal-spread'|'none'}
 */
export function getReflowLayoutMode(authoredSize, targetSize) {
  if (!needsReflow(authoredSize, targetSize)) {
    return 'none';
  }
  
  const aspectChange = detectAspectChange(authoredSize, targetSize);
  
  switch (aspectChange) {
    case 'horizontal-to-vertical': return 'vertical-stack';
    case 'vertical-to-horizontal': return 'horizontal-spread';
    default: return 'proportional';
  }
}

// Default export for convenience
export default {
  calculateReflowLayout,
  needsReflow,
  getReflowLayoutMode,
  getDefaultReflowMetadata,
  ensureReflowMetadata,
  REFLOW_CONFIG
};
