// Tests for flipOffset.js — unflipReportedXY.
//
// What this guards
// ────────────────
// `unflipReportedXY` is the single source of truth for converting
// Konva's reported `node.x()` / `node.y()` (in the post-offset frame)
// back to the un-offset top-left coordinates we store on the element.
// Four call sites use it: ImageElement.onDragEnd, ImageElement
// .onTransformEnd, TextElement.onDragEnd, TextElement.onTransformEnd.
//
// Any drift between this helper's math and what those call sites
// expect produces drag jumps or transform-end position jumps —
// exactly the bugs documented in [[Refinements_2026-05-22]] Section 8
// (text transformer scale fix) and the broader rotation-pivot
// center-offset refactor (Section 3 of the same note).
//
// The contract being tested
// ─────────────────────────
// After the May 22 refactor that made the offset unconditionally
// bbox-center (instead of conditional-on-flip), this helper does an
// UNCONDITIONAL `node.x() - W/2`, `node.y() - H/2`. The flipX/flipY
// arguments are unused. The unconditional behavior is the heart of
// the fix; if a future refactor accidentally re-introduced a
// conditional branch, these tests would catch it.
//
// We construct a minimal Konva-node-like stub rather than mounting
// a real Konva Stage. The function only calls `.x()` and `.y()` on
// the node, so a tiny stub is sufficient.

import { unflipReportedXY } from './flipOffset';

// Tiny stub mimicking the relevant slice of Konva's Node API. The
// real Node has dozens of methods we don't care about here.
function makeNodeStub(x, y) {
  return {
    x: () => x,
    y: () => y,
  };
}

describe('unflipReportedXY', () => {
  it('subtracts half-width from node.x and half-height from node.y', () => {
    // With offset at bbox center, a Konva node whose top-left should
    // render at (10, 20) reports x() / y() in the post-offset frame.
    // For a 100×60 element, that means node.x() = 60 and node.y() =
    // 50 (top-left + offset). The helper inverts the offset:
    // 60 - 50 = 10, 50 - 30 = 20.
    const node = makeNodeStub(60, 50);
    expect(unflipReportedXY(node, 100, 60, false, false)).toEqual({
      x: 10,
      y: 20,
    });
  });

  it('produces identical output regardless of flipX/flipY flags (the regression contract)', () => {
    // This is the core invariant the May 22 rotation-pivot refactor
    // established: offset is always center, so the unflip math is
    // unconditional. Previously the helper returned different values
    // depending on flip state, which gave the rotation-pivot bug
    // (pivot was top-left for non-flipped, center for flipped).
    //
    // If a future change re-introduces a conditional branch, this
    // test fails for the flipped cases.
    const node = makeNodeStub(60, 50);
    const baseline = unflipReportedXY(node, 100, 60, false, false);
    expect(unflipReportedXY(node, 100, 60, true, false)).toEqual(baseline);
    expect(unflipReportedXY(node, 100, 60, false, true)).toEqual(baseline);
    expect(unflipReportedXY(node, 100, 60, true, true)).toEqual(baseline);
  });

  it('handles odd dimensions cleanly (half-pixel math)', () => {
    // 99 / 2 = 49.5 — the helper doesn't round; callers store the
    // fractional value and Konva handles sub-pixel positioning. This
    // pins the no-rounding behavior; a future refactor adding
    // Math.round here would shift elements by half a pixel on every
    // drag-end, accumulating over many drags.
    const node = makeNodeStub(50, 30);
    expect(unflipReportedXY(node, 99, 61, false, false)).toEqual({
      x: 50 - 49.5,
      y: 30 - 30.5,
    });
  });

  it('handles zero dimensions (no division-by-zero or NaN)', () => {
    // Empty text elements (no text typed yet) can briefly have
    // width=0 mid-render. The helper shouldn't blow up — it should
    // just return node.x() and node.y() unchanged (minus 0 = same).
    const node = makeNodeStub(42, 17);
    expect(unflipReportedXY(node, 0, 0, false, false)).toEqual({
      x: 42,
      y: 17,
    });
  });

  it('handles negative node coordinates (off-canvas positions)', () => {
    // An element dragged outside the print zone can end up at
    // negative coords. The math should still work — subtraction is
    // signed.
    const node = makeNodeStub(-10, -20);
    expect(unflipReportedXY(node, 100, 60, false, false)).toEqual({
      x: -60,
      y: -50,
    });
  });
});
