// 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 = 26;  // narrow dimension
export const TILE_H = 48;  // long dimension
export const GAP = 2;      // small gap between tiles

const MARGIN = 40;

// Direction vectors for chain growth
const DIRS = [
  { dx: 1, dy: 0 },   // 0: right
  { dx: 0, dy: 1 },   // 1: down
  { dx: -1, dy: 0 },  // 2: left
  { dx: 0, dy: -1 },  // 3: 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;

    // Tile dimensions based on orientation
    let w, h;
    if (isHorizontal) {
      if (isDouble) {
        w = TILE_W; h = TILE_H; // perpendicular: narrow along chain, tall across
      } else {
        w = TILE_H; h = TILE_W; // aligned: long along chain, narrow across
      }
    } else {
      if (isDouble) {
        w = TILE_H; h = TILE_W; // perpendicular: wide across chain, narrow along
      } else {
        w = TILE_W; h = TILE_H; // aligned: narrow across, long along chain
      }
    }

    // flipPips: when chain goes LEFT or UP, the "left" value is on the
    // trailing side (right or bottom on screen), so renderer must flip
    const flipPips = (dirIdx === 2 || dirIdx === 3);

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

    // 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 (same dir)
      const nextW = isHorizontal ? (nextIsDouble ? TILE_W : TILE_H) : (nextIsDouble ? TILE_H : TILE_W);
      const nextH = isHorizontal ? (nextIsDouble ? TILE_H : TILE_W) : (nextIsDouble ? TILE_W : TILE_H);
      const nextHalf = isHorizontal ? nextW / 2 : nextH / 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
        const oldDirIdx = dirIdx;
        dirIdx = (dirIdx + 1) % 4;
        const newDir = DIRS[dirIdx];
        const newIsHorizontal = newDir.dx !== 0;

        // Current tile's cross-axis half (perpendicular to old direction = along new direction)
        const curCrossHalf = isHorizontal ? h / 2 : w / 2;

        // Next tile dimensions in NEW direction
        const newNextW = newIsHorizontal ? (nextIsDouble ? TILE_W : TILE_H) : (nextIsDouble ? TILE_H : TILE_W);
        const newNextH = newIsHorizontal ? (nextIsDouble ? TILE_H : TILE_W) : (nextIsDouble ? TILE_W : TILE_H);
        // Next tile's half in new chain direction
        const newNextHalf = newIsHorizontal ? newNextW / 2 : newNextH / 2;

        // Perpendicular offset: clear current tile's cross edge + gap + next tile's chain half
        const perpOffset = curCrossHalf + GAP + newNextHalf;
        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.3, needed));
}
