#pragma once

#include <QPoint>
#include <QPointF>
#include <QRect>
#include <QRectF>
#include <QSize>
#include <QVector2D>

// Immutable snapshot of the world <-> widget transform for one viewport state
// (REQ-GW-COORDS). Tiles are square; the two factories below differ only in how
// the tile size and the left edge are derived, and everything downstream of that
// is shared.
//
// The transform is a value: it is constructed from the viewport size and the view
// state, and never observes them again. A caller therefore builds one per frame
// (or per event) rather than holding one across a resize or a scroll, which would
// silently go stale.
class WorldCoordinates
{
public:
    // The scrolling game world: the tile size is whatever makes the world height
    // exactly fill the viewport height (REQ-GW-TILE-SIZE, no zoom per
    // REQ-UI-NO-ZOOM), and the view pans horizontally. `viewCenterX_tiles` is the
    // world X at the center of the viewport, matching how the scroll position is
    // stored and clamped (REQ-GW-SCROLL-LIMIT).
    static WorldCoordinates scrolling(QSize widgetSize_px, int worldHeight_tiles,
                                      float viewCenterX_tiles);

    // A whole world shown at once with no scrolling, as the balancing tool's arena
    // does: the tile size is whichever axis is the tighter fit, so nothing is cut
    // off, and the world origin sits at the widget's top-left. A viewport wider
    // than the fitted world leaves empty space to the right rather than centering.
    static WorldCoordinates fitToWorld(QSize widgetSize_px, int worldWidth_tiles,
                                       int worldHeight_tiles);

    // Side length of one tile in pixels. Always positive: a degenerate world or
    // viewport size falls back to 1.0 so no conversion below divides by zero.
    float getTilePx() const;
    float getViewportWidthTiles() const;
    // World X (tiles) at the left edge of the viewport.
    float getViewLeftTiles() const;

    QPointF   worldToWidget(QVector2D worldPos) const;
    QPointF   tileToWidget(QPoint tile) const;
    QPoint    widgetToTile(QPoint widgetPoint) const;
    QVector2D widgetToWorld(QPoint widgetPoint) const;
    // Widget-space rect covering the whole of `tile`.
    QRectF    tileRect(QPoint tile) const;

    // Tile-space rect of everything currently on screen, widened by one column on
    // each side so items straddling an edge are still drawn.
    QRect     getViewportRect() const;

private:
    WorldCoordinates(float tilePx, float viewportWidth_px, float viewLeft_tiles,
                     int worldHeight_tiles);

    float m_tilePx;
    float m_viewportWidthTiles;
    float m_viewLeftTiles;
    int   m_worldHeightTiles;
};
