// card_drag — pure implementation. See card_drag.h.

#include "core/ui/card_drag.h"

namespace reasampler::ui {

namespace {

bool insideClient(int px, int py, const PanelClientRect& c) {
    return px >= c.x && px < c.x + c.width &&
           py >= c.y && py < c.y + c.height;
}

} // namespace

CardGesture decideCardGesture(int px, int py, const PanelClientRect& client,
                              const DragState& state, const DragModifiers& mods) {
    if (!state.dragging || !state.hasArmedSamples) return CardGesture::None;

    if (!insideClient(px, py, client)) return CardGesture::OsDragOut;

    if (mods.region == DropRegion::OtherBankOrTab)
        return mods.ctrl ? CardGesture::Copy : CardGesture::Move;

    if (mods.region == DropRegion::SameBankGrid) {
        if (mods.alt && mods.slotOccupied) return CardGesture::Replace;
        return CardGesture::Reorder;
    }

    return CardGesture::None;
}

CursorCue cursorForGesture(CardGesture g) {
    switch (g) {
        case CardGesture::OsDragOut: return CursorCue::OsDragOut;
        case CardGesture::Move:      return CursorCue::Move;
        case CardGesture::Copy:      return CursorCue::Copy;
        case CardGesture::Reorder:   return CursorCue::Reorder;
        case CardGesture::Replace:   return CursorCue::Replace;
        case CardGesture::None:      return CursorCue::Default;
    }
    return CursorCue::Default;
}

std::vector<SlotCellRect> computeSlotRects(int maxSlot, int panelWidth,
                                           const GridSpec& spec) {
    std::vector<SlotCellRect> rects;
    if (maxSlot < 0) return rects;

    const int cols = columnsForWidth(panelWidth, spec);
    const int count = maxSlot + 1;
    rects.reserve(static_cast<std::size_t>(count));

    for (int slot = 0; slot < count; ++slot) {
        const int col = slot % cols;
        const int row = slot / cols;
        SlotCellRect r;
        r.slot   = slot;
        r.x      = spec.gap + col * (spec.cellWidth + spec.gap);
        r.y      = spec.gap + row * (spec.cellHeight + spec.gap);
        r.width  = spec.cellWidth;
        r.height = spec.cellHeight;
        rects.push_back(r);
    }
    return rects;
}

std::vector<SlotCellRect> computeSlotRectsForDrop(int maxSlot, int panelWidth,
                                                   const GridSpec& spec) {
    const int cols = columnsForWidth(panelWidth, spec);
    const int firstTrailing = maxSlot + 1;
    const int newMax = firstTrailing + cols - 1;  // one full trailing row
    return computeSlotRects(newMax, panelWidth, spec);
}

int hitTestSlot(int px, int py, const std::vector<SlotCellRect>& rects) {
    for (const SlotCellRect& r : rects) {
        if (px >= r.x && px < r.x + r.width &&
            py >= r.y && py < r.y + r.height)
            return r.slot;
    }
    return -1;
}

} // namespace reasampler::ui
