type SelectionSnapshot = {
  activeElement: Element | null;
  ranges: Range[];
};

function captureSelectionSnapshot(): SelectionSnapshot | null {
  if (typeof window === 'undefined' || typeof document === 'undefined') {
    return null;
  }

  const selection = window.getSelection();
  const ranges: Range[] = [];

  if (selection) {
    for (let index = 0; index < selection.rangeCount; index += 1) {
      ranges.push(selection.getRangeAt(index).cloneRange());
    }
  }

  return {
    activeElement: document.activeElement,
    ranges,
  };
}

function restoreSelectionSnapshot(snapshot: SelectionSnapshot | null) {
  if (!snapshot || typeof window === 'undefined') {
    return;
  }

  const selection = window.getSelection();
  selection?.removeAllRanges();
  snapshot.ranges.forEach((range) => selection?.addRange(range));

  const target = snapshot.activeElement;

  if (target instanceof HTMLElement || target instanceof SVGElement) {
    try {
      target.focus({ preventScroll: true });
    } catch {
      target.focus();
    }
  }
}

function copyUsingTextareaFallback(text: string) {
  if (
    typeof window === 'undefined' ||
    typeof document === 'undefined' ||
    typeof document.execCommand !== 'function' ||
    !document.body
  ) {
    return false;
  }

  const snapshot = captureSelectionSnapshot();
  const textarea = document.createElement('textarea');
  textarea.value = text;
  textarea.tabIndex = -1;
  textarea.readOnly = true;
  textarea.setAttribute('readonly', '');
  textarea.setAttribute('aria-hidden', 'true');
  textarea.style.position = 'fixed';
  textarea.style.top = '0';
  textarea.style.left = '0';
  textarea.style.width = '1px';
  textarea.style.height = '1px';
  textarea.style.padding = '0';
  textarea.style.border = '0';
  textarea.style.outline = '0';
  textarea.style.boxShadow = 'none';
  textarea.style.background = 'transparent';
  textarea.style.opacity = '0';
  textarea.style.pointerEvents = 'none';
  textarea.style.fontSize = '16px';
  textarea.style.whiteSpace = 'pre';
  textarea.style.userSelect = 'text';
  textarea.style.webkitUserSelect = 'text';

  document.body.appendChild(textarea);

  try {
    try {
      textarea.focus({ preventScroll: true });
    } catch {
      textarea.focus();
    }

    textarea.select();
    textarea.selectionStart = 0;
    textarea.selectionEnd = text.length;
    textarea.setSelectionRange(0, text.length);
    return document.execCommand('copy');
  } catch {
    return false;
  } finally {
    textarea.remove();
    restoreSelectionSnapshot(snapshot);
  }
}

export async function copyTextToClipboard(text: string): Promise<void> {
  if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {
    try {
      await navigator.clipboard.writeText(text);
      return;
    } catch {
      // Fall back when the browser exposes the API but rejects the write.
    }
  }

  if (copyUsingTextareaFallback(text)) {
    return;
  }

  throw new Error('브라우저가 클립보드 복사를 차단했습니다.');
}
