const TILE_W = 26;
const TILE_H = 50;
const DOUBLE_W = 26;
const DOUBLE_H = 26;
const GAP = 3;
const MARGIN = 16;

const DIRECTIONS = [
  { dx: 1, dy: 0 },
  { dx: 0, dy: 1 },
  { dx: -1, dy: 0 },
  { dx: 0, dy: -1 }
];

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

  const tiles = [];
  let dirIdx = 0;
  let cx = canvasW / 2;
  let cy = canvasH / 2;

  for (let i = 0; i < chain.length; i++) {
    const tile = chain[i];
    const dbl = tile.left === tile.right;
    const dir = DIRECTIONS[dirIdx];

    const w = dbl ? DOUBLE_W : (dir.dx !== 0 ? TILE_H : TILE_W);
    const h = dbl ? DOUBLE_H : (dir.dx !== 0 ? TILE_W : TILE_H);
    const rotation = dbl ? (dir.dx !== 0 ? 0 : 90) : (dir.dx !== 0 ? 90 : 0);

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

    const stepW = dbl ? DOUBLE_W : (dir.dx !== 0 ? TILE_H : TILE_W);
    const stepH = dbl ? DOUBLE_H : (dir.dy !== 0 ? TILE_H : TILE_W);
    const advance = (dir.dx !== 0 ? stepW : stepH) + GAP;

    let nextX = cx + dir.dx * advance;
    let nextY = cy + dir.dy * advance;

    if (i < chain.length - 1 && wouldExceedBounds(nextX, nextY, chain[i + 1], dirIdx, canvasW, canvasH)) {
      dirIdx = (dirIdx + 1) % 4;
      const newDir = DIRECTIONS[dirIdx];
      const offsetDist = (dir.dx !== 0 ? TILE_W : TILE_H) + GAP * 2;
      cx += newDir.dx * offsetDist;
      cy += newDir.dy * offsetDist;
    } else {
      cx = nextX;
      cy = nextY;
    }
  }

  const bounds = getBounds(tiles);
  const offsetX = (canvasW - (bounds.maxX + bounds.minX)) / 2 - bounds.minX;
  const offsetY = (canvasH - (bounds.maxY + bounds.minY)) / 2 - bounds.minY;
  tiles.forEach(t => { t.x += offsetX; t.y += offsetY; });

  const endpoints = {
    left: tiles.length > 0 ? getEndpointPos(tiles[0], 'left', chain) : null,
    right: tiles.length > 0 ? getEndpointPos(tiles[tiles.length - 1], 'right', chain) : null
  };

  return { tiles, endpoints };
}

function wouldExceedBounds(nx, ny, nextTile, dirIdx, cw, ch) {
  const dir = DIRECTIONS[dirIdx];
  const dbl = nextTile.left === nextTile.right;
  const halfW = (dbl ? DOUBLE_W : (dir.dx !== 0 ? TILE_H : TILE_W)) / 2;
  const halfH = (dbl ? DOUBLE_H : (dir.dy !== 0 ? TILE_H : TILE_W)) / 2;

  return (nx - halfW < MARGIN || nx + halfW > cw - MARGIN ||
          ny - halfH < MARGIN || ny + halfH > ch - MARGIN);
}

function getBounds(tiles) {
  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 getEndpointPos(layoutTile, side, chain) {
  const dir = side === 'left' ? -1 : 1;
  const t = layoutTile;
  const rot = t.rotation;
  let ex, ey;

  if (rot === 90) {
    ex = t.x + dir * (t.w / 2 + 14);
    ey = t.y;
  } else {
    ex = t.x;
    ey = t.y + dir * (t.h / 2 + 14);
  }

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

export function getSnapRadius() { return 55; }

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

export { TILE_W, TILE_H, DOUBLE_W, DOUBLE_H, GAP };
