let _rubberBand, _grid, _gridContainer;
let _state, _cb;

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

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

export function resetAnchor() {
  lastSelectedIdx = null;
  keyboardTargetIdx = null;
  keyboardExtendBaseSelection = null;
}

export function isKeyboardTarget(idx) {
  return keyboardTargetIdx === idx;
}

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

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

// 카드에 부착할 클릭 핸들러 (this = card element)
export function onCardClick(e) {
  if (e.target.closest('.card-delete')) return;
  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;
    }
  }

  keyboardTargetIdx = idx;
  keyboardExtendBaseSelection = null;
  _cb.refreshCardSelection();
  _cb.updateSelCount();
}

export function handleKeyboardNavigation(code, { extend = false } = {}) {
  if (!_state?.files.length) return false;

  const currentIdx = _getCurrentKeyboardIndex(code);
  const nextIdx = _getNextKeyboardIndex(currentIdx, code);
  if (nextIdx === null) return false;

  if (extend) {
    if (lastSelectedIdx === null) lastSelectedIdx = currentIdx ?? nextIdx;
    if (!keyboardExtendBaseSelection) {
      keyboardExtendBaseSelection = new Set(_state.selectedIdxs);
    }
    _selectKeyboardRange(lastSelectedIdx, nextIdx, keyboardExtendBaseSelection);
  } else {
    _state.selectedIdxs.clear();
    _state.selectedIdxs.add(nextIdx);
    lastSelectedIdx = nextIdx;
    keyboardExtendBaseSelection = null;
  }

  keyboardTargetIdx = nextIdx;
  _cb.refreshCardSelection();
  _cb.updateSelCount();
  _scrollKeyboardTargetIntoView(code, nextIdx);
  return true;
}

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

function _selectRange(idx) {
  if (lastSelectedIdx === null) {
    _state.selectedIdxs.clear();
    _state.selectedIdxs.add(idx);
    lastSelectedIdx = idx;
    keyboardExtendBaseSelection = null;
    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 클릭으로 변경하지 않음
  keyboardExtendBaseSelection = null;
}

function _selectKeyboardRange(anchorIdx, targetIdx, baseSelection) {
  const start = Math.min(anchorIdx, targetIdx);
  const end   = Math.max(anchorIdx, targetIdx);
  _state.selectedIdxs.clear();
  baseSelection.forEach(idx => {
    if (_isValidIndex(idx)) _state.selectedIdxs.add(idx);
  });
  for (let i = start; i <= end; i++) _state.selectedIdxs.add(i);
}

function _getCurrentKeyboardIndex(code) {
  if (_isValidIndex(keyboardTargetIdx)) return keyboardTargetIdx;
  if (_state.selectedIdxs.size) return Math.min(..._state.selectedIdxs);
  return null;
}

function _getNextKeyboardIndex(currentIdx, code) {
  const lastIdx = _state.files.length - 1;

  if (currentIdx === null) {
    return (code === 'ArrowLeft' || code === 'ArrowUp' || code === 'End')
      ? lastIdx
      : 0;
  }

  if (code === 'Home') return 0;
  if (code === 'End') return lastIdx;
  if (code === 'ArrowLeft') return Math.max(0, currentIdx - 1);
  if (code === 'ArrowRight') return Math.min(lastIdx, currentIdx + 1);
  const columnCount = _getColumnCount();
  if (code === 'ArrowUp') return Math.max(0, currentIdx - columnCount);
  if (code === 'ArrowDown') return Math.min(lastIdx, currentIdx + columnCount);
  return null;
}

function _getColumnCount() {
  const cards = Array.from(_grid.children).filter(card => card.classList.contains('card'));
  if (!cards.length) return 1;

  const firstTop = cards[0].getBoundingClientRect().top;
  const firstRowCount = cards.findIndex(card =>
    Math.abs(card.getBoundingClientRect().top - firstTop) > 2
  );
  return firstRowCount === -1 ? cards.length : Math.max(1, firstRowCount);
}

function _scrollCardIntoView(idx) {
  const card = _grid.querySelector(`.card[data-idx="${idx}"]`);
  card?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
}

function _scrollKeyboardTargetIntoView(code, idx) {
  if (code === 'Home') {
    _gridContainer.scrollTop = 0;
    return;
  }
  if (code === 'End') {
    _gridContainer.scrollTop = _gridContainer.scrollHeight - _gridContainer.clientHeight;
    return;
  }
  _scrollCardIntoView(idx);
}

function _isValidIndex(idx) {
  return Number.isInteger(idx) && idx >= 0 && idx < _state.files.length;
}

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;
    keyboardTargetIdx = null;
    keyboardExtendBaseSelection = 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();
}
