#pragma once
#include <wx/dc.h>
#include <unordered_set>
#include "canvas/CanvasState.h"
#include "model/TrackPiece.h"
#include "model/PlacedPiece.h"
#include "model/SceneryItem.h"
#include "model/PlacedScenery.h"

namespace MC {

struct ViewTransform {
    double scale = 0.4;
    double panX  = 0.0;
    double panY  = 0.0;

    wxPoint ToScreen(const Vec2& mm) const {
        return {
            static_cast<int>(mm.x * scale + panX),
            static_cast<int>(mm.y * scale + panY)
        };
    }

    Vec2 ToWorld(const wxPoint& px) const {
        return { (px.x - panX) / scale, (px.y - panY) / scale };
    }

    void ZoomAt(double factor, const wxPoint& screenPivot) {
        Vec2 worldPivot = ToWorld(screenPivot);
        scale *= factor;
        if (scale < 0.3)  scale = 0.3;
        if (scale > 20.0) scale = 20.0;
        panX = screenPivot.x - worldPivot.x * scale;
        panY = screenPivot.y - worldPivot.y * scale;
    }
};

class Renderer {
public:
    void Draw(wxDC& dc, const CanvasState& state,
              const ViewTransform& view, const wxSize& clientSize);

    void DrawPiece(wxDC& dc, const PlacedPiece& placed, const TrackPiece& def,
                   const ViewTransform& view, bool selected = false,
                   bool showDots = true, bool inTunnel = false);

    void DrawScenery(wxDC& dc, const PlacedScenery& placed, const SceneryItem& def,
                     const ViewTransform& view, bool selected = false);

    void DrawSceneryGhost(wxDC& dc, const SceneryItem& def,
                          const Transform2D& transform, const ViewTransform& view);

    void DrawGhost(wxDC& dc, const TrackPiece& def,
                   const Transform2D& transform, const ViewTransform& view);

private:
    void DrawPieceRails(wxDC& dc, const PlacedPiece& placed,
                        const TrackPiece& def, const ViewTransform& view);

    void DrawGrid(wxDC& dc, const CanvasState& state,
                  const ViewTransform& view, const wxSize& clientSize);

    void DrawConnectionDots(wxDC& dc, const PlacedPiece& placed,
                            const TrackPiece& def, const ViewTransform& view);

    void DrawHelices(wxDC& dc, const CanvasState& state, const ViewTransform& view);

    void DrawSceneryShapes(wxDC& dc, const SceneryItem& def,
                           const Transform2D& transform,
                           const ViewTransform& view, bool selected,
                           double scaleX = 1.0, double scaleY = 1.0);

    // Pieces directly joined to a helix stub. We suppress the elevation
    // tint for these so pieces sitting on the helix top deck don't appear
    // saturated orange; they're "deck" pieces, not "ramp" pieces.
    std::unordered_set<int> m_helixAttachedIds;

    // Set at the top of Draw() so per-piece helpers (DrawPiece) can look up
    // level attributes (track color, height). Valid only during a Draw call.
    const CanvasState* m_state = nullptr;
};

} // namespace MC

