let _rubberBand, _grid;
let _state, _cb;

let rbActive = false;
let rbStartX = 0;
let rbStartY = 0;
let _rafPending   = false;
let _lastMoveEvent = null;

let lastSelectedIdx = null;
let _rbStartSelection = new Set(); // 러버밴드 시작 시점의 선택 스냅샷

export function resetAnchor() {
  lastSelectedIdx = null;
}

export function init({ gridContainer, rubberBand, grid, state, callbacks }) {
  _rubberBand = rubberBand;
  _grid       = grid;
  _state      = state;
  _cb         = callbacks;

  gridContainer.addEventListener('mousedown', _onStart);
  window.addEventListener('mousemove', _onMove);
  window.addEventListener('mouseup',   _onEnd);
}

// 카드에 부착할 클릭 핸들러 (this = card element)
export function onCardClick(e) {
  e.stopPropagation();
  const idx = parseInt(this.dataset.idx);
  const isCtrl = e.ctrlKey || e.metaKey;

  if (e.shiftKey && isCtrl) {
    // Shift + Ctrl/Cmd → Ctrl 동작으로 처리
    _toggle(idx);
  } else if (e.shiftKey) {
    _selectRange(idx);
  } else if (isCtrl) {
    _toggle(idx);
  } else {
    // 수식 키 없음: 해당 카드만 단독 선택, 이미 단독 선택 중이면 해제
    if (_state.selectedIdxs.has(idx) && _state.selectedIdxs.size === 1) {
      _state.selectedIdxs.clear();
      lastSelectedIdx = null;
    } else {
      _state.selectedIdxs.clear();
      _state.selectedIdxs.add(idx);
      lastSelectedIdx = idx;
    }
  }

  _cb.refreshCardSelection();
  _cb.updateSelCount();
}

function _toggle(idx) {
  if (_state.selectedIdxs.has(idx)) {
    _state.selectedIdxs.delete(idx);
    lastSelectedIdx = null;
  } else {
    _state.selectedIdxs.add(idx);
    lastSelectedIdx = idx;
  }
}

function _selectRange(idx) {
  if (lastSelectedIdx === null) {
    _state.selectedIdxs.clear();
    _state.selectedIdxs.add(idx);
    lastSelectedIdx = idx;
    return;
  }
  const start = Math.min(lastSelectedIdx, idx);
  const end   = Math.max(lastSelectedIdx, idx);
  _state.selectedIdxs.clear();
  for (let i = start; i <= end; i++) _state.selectedIdxs.add(i);
  // anchor(lastSelectedIdx)는 Shift 클릭으로 변경하지 않음
}

function _onStart(e) {
  if (e.target.closest('.card')) return;
  if (e.target.closest('button, input, label')) return;
  if (e.button !== 0) return;

  rbActive = true;
  rbStartX = e.clientX;
  rbStartY = e.clientY;

  Object.assign(_rubberBand.style, {
    display: 'block',
    left: rbStartX + 'px',
    top:  rbStartY + 'px',
    width:  '0px',
    height: '0px',
  });

  const preserve = e.shiftKey || e.ctrlKey || e.metaKey;
  _rbStartSelection = new Set(_state.selectedIdxs); // 토글 기준점 스냅샷
  if (!preserve) {
    _state.selectedIdxs.clear();
    _rbStartSelection.clear();
    lastSelectedIdx = null;
    _cb.refreshCardSelection();
  }
}

function _onMove(e) {
  if (!rbActive) return;
  _lastMoveEvent = e;
  if (!_rafPending) {
    _rafPending = true;
    requestAnimationFrame(_processMove);
  }
}

function _processMove() {
  _rafPending = false;
  const e = _lastMoveEvent;
  if (!rbActive || !e) return;

  const left   = Math.min(rbStartX, e.clientX);
  const top    = Math.min(rbStartY, e.clientY);
  const width  = Math.abs(e.clientX - rbStartX);
  const height = Math.abs(e.clientY - rbStartY);

  Object.assign(_rubberBand.style, {
    left: left + 'px', top: top + 'px',
    width: width + 'px', height: height + 'px',
  });

  const sel = { left, top, right: left + width, bottom: top + height };
  const shiftToggle = e.shiftKey && !e.ctrlKey && !e.metaKey;
  const preserve    = e.ctrlKey || e.metaKey;
  Array.from(_grid.children).forEach((card, i) => {
    const r = card.getBoundingClientRect();
    const overlaps = !(r.right < sel.left || r.left > sel.right ||
                       r.bottom < sel.top  || r.top  > sel.bottom);
    if (shiftToggle) {
      // 러버밴드 안: 시작 시점 기준으로 토글 (밖: 시작 시점 상태 복원)
      if (overlaps ? !_rbStartSelection.has(i) : _rbStartSelection.has(i)) {
        _state.selectedIdxs.add(i);
      } else {
        _state.selectedIdxs.delete(i);
      }
    } else if (overlaps) {
      _state.selectedIdxs.add(i);
    } else if (!preserve) {
      _state.selectedIdxs.delete(i);
    }
  });

  _cb.refreshCardSelection();
  _cb.updateSelCount();
}

function _onEnd() {
  if (!rbActive) return;
  rbActive = false;
  _rubberBand.style.display = 'none';
  _cb.updateSelCount();
}
