// Domino chain layout engine
// Chain starts from center, grows outward. Turns when hitting bounds.
// Doubles are perpendicular to chain direction.
// Non-doubles align with chain direction (landscape in horizontal chain).

export const TILE_W = 24;  // narrow dimension
export const TILE_H = 48;  // long dimension
export const GAP = 1;      // flush contact between connected tiles on board

const MARGIN = 30;

// Direction vectors for chain growth
const DIRS = [
  { dx: 1, dy: 0 },   // right
  { dx: 0, dy: 1 },   // down
  { dx: -1, dy: 0 },  // left
  { dx: 0, dy: -1 },  // up
];

export function computeLayout(chain, canvasW, canvasH) {
  if (chain.length === 0) {
    return {
      tiles: [],
      endpoints: { left: null, right: null },
      bounds: { minX: 0, minY: 0, maxX: canvasW, maxY: canvasH }
    };
  }

  const tiles = [];
  let dirIdx = 0; // start going right
  let cx = 0, cy = 0; // build from origin, center later

  for (let i = 0; i < chain.length; i++) {
    const piece = chain[i];
    const isDouble = piece.left === piece.right;
    const dir = DIRS[dirIdx];
    const isHorizontal = dir.dx !== 0; // chain goes left/right

    // Tile rendered dimensions (already in screen orientation, no rotation needed)
    let w, h;
    if (isHorizontal) {
      // Chain goes horizontally
      if (isDouble) {
        // Doubles perpendicular: narrow along chain, tall across
        w = TILE_W;
        h = TILE_H;
      } else {
        // Non-doubles aligned: long along chain, narrow across
        w = TILE_H;
        h = TILE_W;
      }
    } else {
      // Chain goes vertically
      if (isDouble) {
        // Doubles perpendicular: wide across chain, narrow along
        w = TILE_H;
        h = TILE_W;
      } else {
        // Non-doubles aligned: narrow across, long along chain
        w = TILE_W;
        h = TILE_H;
      }
    }

    tiles.push({ tile: piece, x: cx, y: cy, w, h, rotation: 0, isDouble, dirIdx });

    // Calculate advance to next tile position
    if (i < chain.length - 1) {
      const nextPiece = chain[i + 1];
      const nextIsDouble = nextPiece.left === nextPiece.right;

      // Half-extent of current tile in chain direction
      const curHalf = isHorizontal ? w / 2 : h / 2;
      // Half-extent of next tile in chain direction
      let nextHalf;
      if (isHorizontal) {
        nextHalf = nextIsDouble ? TILE_W / 2 : TILE_H / 2;
      } else {
        nextHalf = nextIsDouble ? TILE_W / 2 : TILE_H / 2;
      }

      const advance = curHalf + GAP + nextHalf;
      const nextX = cx + dir.dx * advance;
      const nextY = cy + dir.dy * advance;

      // Check bounds - use virtual space proportional to canvas
      const boundW = canvasW * 2;
      const boundH = canvasH * 2;

      if (Math.abs(nextX) > boundW / 2 - MARGIN || Math.abs(nextY) > boundH / 2 - MARGIN) {
        // Turn clockwise
        dirIdx = (dirIdx + 1) % 4;
        const newDir = DIRS[dirIdx];
        // Offset perpendicular from current position to start new row
        const perpOffset = (TILE_H / 2 + GAP + TILE_H / 2);
        cx += newDir.dx * perpOffset;
        cy += newDir.dy * perpOffset;
      } else {
        cx = nextX;
        cy = nextY;
      }
    }
  }

  // Center the whole chain in canvas
  const bounds = computeBounds(tiles);
  const chainW = bounds.maxX - bounds.minX;
  const chainH = bounds.maxY - bounds.minY;
  const offsetX = canvasW / 2 - (bounds.minX + chainW / 2);
  const offsetY = canvasH / 2 - (bounds.minY + chainH / 2);
  tiles.forEach(t => { t.x += offsetX; t.y += offsetY; });

  const finalBounds = computeBounds(tiles);

  // Compute endpoints
  const endpoints = {
    left: getEndpoint(tiles, chain, 'left'),
    right: getEndpoint(tiles, chain, 'right')
  };

  return { tiles, endpoints, bounds: finalBounds };
}

function computeBounds(tiles) {
  if (tiles.length === 0) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
  for (const t of tiles) {
    minX = Math.min(minX, t.x - t.w / 2);
    minY = Math.min(minY, t.y - t.h / 2);
    maxX = Math.max(maxX, t.x + t.w / 2);
    maxY = Math.max(maxY, t.y + t.h / 2);
  }
  return { minX, minY, maxX, maxY };
}

function getEndpoint(tiles, chain, side) {
  if (tiles.length === 0) return null;

  const idx = side === 'left' ? 0 : tiles.length - 1;
  const lt = tiles[idx];
  const dir = DIRS[lt.dirIdx];
  const isHorizontal = dir.dx !== 0;

  // The endpoint is beyond the tile in the direction the chain is going
  // For 'left' endpoint, it's in the OPPOSITE direction from the first tile
  // For 'right' endpoint, it's in the SAME direction from the last tile
  const sign = side === 'left' ? -1 : 1;
  const halfExtent = isHorizontal ? lt.w / 2 : lt.h / 2;
  const offset = halfExtent + 18; // gap for the glow indicator

  const ex = lt.x + dir.dx * sign * offset;
  const ey = lt.y + dir.dy * sign * offset;

  const endValue = side === 'left' ? chain[0].left : chain[chain.length - 1].right;
  return { x: ex, y: ey, value: endValue, end: side };
}

export function getSnapRadius() { return 60; }

export function hitTestEndpoint(px, py, endpoint) {
  if (!endpoint) return false;
  const dx = px - endpoint.x;
  const dy = py - endpoint.y;
  return (dx * dx + dy * dy) < getSnapRadius() * getSnapRadius();
}

export function getAutoZoom(bounds, canvasW, canvasH) {
  const chainW = (bounds.maxX - bounds.minX) + 80;
  const chainH = (bounds.maxY - bounds.minY) + 80;
  const scaleX = canvasW / chainW;
  const scaleY = canvasH / chainH;
  const needed = Math.min(scaleX, scaleY);
  return Math.min(1, Math.max(0.35, needed));
}
