// Hit-test golden (P4.4): lock the touch→cell mapping `BoardLayout.point_to_cell`
// as the exact inverse of `cell_frame`. The two are written independently — one
// multiplies a cell index by cell_size, the other divides a point by cell_size
// and truncates — so round-tripping every cell center back to its own cell is a
// real check, not a tautology. BoardView and P5's swap input both reuse this
// mapping, so a drift here would silently send taps/swaps to the wrong cell.
//
// Imports BoardLayout (no GL/stb), not BoardView, so it links headless. It also
// avoids tests/test.sx, whose modules/process.sx → modules/trace.sx pulls in a
// second `Frame` struct that collides with the UI `Frame`. Failure is signalled
// via a non-zero exit code (the runner checks exit code AND stdout).
#import "modules/std.sx";
#import "board.sx";
#import "board_layout.sx";

main :: () -> s32 {
    // 800×600 with no safe inset → a 600px square grid, cell 75, centered: the
    // grid origin lands at (100, 0). Integer math keeps the dump deterministic.
    lay : BoardLayout = ---;
    lay.compute(Frame.make(0.0, 0.0, 800.0, 600.0), EdgeInsets.zero());

    print("grid origin ({},{}) cell {}\n",
        cast(s64) lay.origin.x, cast(s64) lay.origin.y, cast(s64) lay.cell_size);

    fails : s64 = 0;

    // Every cell center must map back to its own cell.
    hits : s64 = 0;
    for 0..BOARD_ROWS: (row) {
        for 0..BOARD_COLS: (col) {
            cf := lay.cell_frame(col, row);
            center := Point.{ x = cf.mid_x(), y = cf.mid_y() };
            if h := lay.point_to_cell(center) {
                if h.col == col and h.row == row { hits += 1; }
            }
        }
    }
    if hits != BOARD_CELLS { fails += 1; }
    print("ok: {}/{} cell centers round-trip\n", hits, BOARD_CELLS);

    // A cell's top-left corner belongs to that cell (the leading edge is
    // inclusive), so corner-of-(3,5) resolves to (3,5).
    corner := Point.{ x = lay.origin.x + 3.0 * lay.cell_size, y = lay.origin.y + 5.0 * lay.cell_size };
    corner_col : s64 = -1;
    corner_row : s64 = -1;
    if h := lay.point_to_cell(corner) { corner_col = h.col; corner_row = h.row; }
    if corner_col != 3 or corner_row != 5 { fails += 1; }
    print("corner maps to ({},{})\n", corner_col, corner_row);

    // Off-board taps reject (null): left of, above, and right of the grid. None
    // should resolve to a cell, so the on-board count must stay 0.
    off_left  := Point.{ x = lay.origin.x - 5.0,                       y = lay.origin.y + 10.0 };
    off_above := Point.{ x = lay.origin.x + 10.0,                      y = lay.origin.y - 5.0 };
    off_right := Point.{ x = lay.origin.x + 8.0 * lay.cell_size + 1.0, y = lay.origin.y + 10.0 };
    on_board : s64 = 0;
    if h := lay.point_to_cell(off_left)  { on_board += 1; print("off_left  hit ({},{})\n", h.col, h.row); }
    if h := lay.point_to_cell(off_above) { on_board += 1; print("off_above hit ({},{})\n", h.col, h.row); }
    if h := lay.point_to_cell(off_right) { on_board += 1; print("off_right hit ({},{})\n", h.col, h.row); }
    if on_board != 0 { fails += 1; }
    print("ok: {} off-board taps resolved to a cell\n", on_board);

    if fails == 0 {
        print("ok: hit-test mapping is the inverse of the layout\n");
        return 0;
    }
    print("FAIL: {} hit-test checks failed\n", fails);
    return 1;
}
