import Foundation

// MARK: - Selection

/// Represents a cursor position and optional selection range on the sheet music.
/// Works like a text editor:
///   - Click places the cursor (thin line) at a measure
///   - Drag creates a selection range (highlighted region)
///   - Shift-click extends the selection from cursor to clicked measure
///   - Click elsewhere moves the cursor (clears any selection)
struct Selection: Equatable {
    /// The cursor position (measure index). -1 means no cursor.
    var cursor: Int = -1

    /// The anchor for a drag selection. -1 means no active selection.
    /// When anchor >= 0 and anchor != cursor, we have a selected range.
    var anchor: Int = -1

    /// Whether there's an active multi-measure selection (not just a cursor)
    var hasSelection: Bool {
        return anchor >= 0 && cursor >= 0 && anchor != cursor
    }

    /// The selected measure range (normalized so start <= end), or nil if just a cursor
    var measureRange: (start: Int, end: Int)? {
        guard hasSelection else { return nil }
        return (min(anchor, cursor), max(anchor, cursor))
    }

    /// Number of selected measures (0 if just a cursor)
    var count: Int {
        guard let range = measureRange else { return 0 }
        return range.end - range.start + 1
    }

    /// Check if a specific measure is within the selection range
    func contains(measure: Int) -> Bool {
        guard let range = measureRange else { return false }
        return measure >= range.start && measure <= range.end
    }

    // MARK: - Operations

    /// Click on a measure — moves the cursor, clears any selection
    mutating func click(measure: Int) {
        cursor = measure
        anchor = -1
    }

    /// Start a drag — sets the anchor
    mutating func startDrag(measure: Int) {
        anchor = measure
        cursor = measure
    }

    /// Continue a drag — moves the cursor while anchor stays put
    mutating func dragTo(measure: Int) {
        cursor = measure
    }

    /// Shift-click — extends selection from cursor (or anchor) to the clicked measure
    mutating func shiftClick(measure: Int) {
        if anchor < 0 {
            anchor = cursor >= 0 ? cursor : measure
        }
        cursor = measure
    }

    /// Clear everything
    mutating func clear() {
        cursor = -1
        anchor = -1
    }

    // MARK: - Static

    static let none = Selection(cursor: -1, anchor: -1)
}
