import { useRef } from 'react';

/**
 * 이 파일이 하는 일:
 * 코드를 입력하는 에디터다. 겉보기엔 줄번호가 붙은 코드 창이지만,
 * 속은 그냥 <textarea> 하나다.
 *
 * 학습 포인트: 왜 Monaco(VS Code 엔진)나 CodeMirror 같은 라이브러리를 안 썼을까?
 * 그 라이브러리들은 수 MB짜리다. 우리가 필요한 건 "고정폭 글꼴 + 탭키 + 줄번호"가 전부인데,
 * 그걸 위해 앱 로딩을 몇 초 늦추는 건 손해다.
 * 라이브러리를 고를 때는 "이게 해 주는 일" 말고 "내가 진짜 필요한 일"을 먼저 적어 보자.
 * 나중에 자동완성·문법 하이라이팅이 정말 필요해지면 그때 바꾸면 된다.
 */
export default function CodeEditor({ value, onChange, readOnly = false, minRows = 12 }) {
  const textareaRef = useRef(null);

  // 줄번호는 줄 수만큼 만들어 준다. 최소 minRows줄은 보이게 해서 창이 쪼그라들지 않게 한다.
  const lineCount = Math.max(value.split('\n').length, minRows);
  const lineNumbers = Array.from({ length: lineCount }, (_, i) => i + 1);

  /**
   * Tab 키 처리.
   * 학습 포인트: textarea는 원래 Tab을 누르면 "다음 입력칸으로 이동"한다(브라우저 기본 동작).
   * 코드 창에서는 들여쓰기가 돼야 하므로 preventDefault()로 기본 동작을 막고
   * 우리가 직접 공백 2칸을 끼워 넣는다.
   */
  function handleKeyDown(event) {
    if (event.key !== 'Tab') {
      return;
    }
    event.preventDefault();
    const textarea = event.target;
    const { selectionStart, selectionEnd } = textarea;
    const next = value.slice(0, selectionStart) + '  ' + value.slice(selectionEnd);
    onChange(next);
    // 값이 바뀐 뒤에 커서를 옮겨야 하므로 다음 렌더 시점으로 미룬다.
    // 커서는 "삽입한 공백 2칸 뒤" = selectionStart + 2.
    // ⚠️ 원래 selectionEnd + 2로 잘못 계산했었다 — 텍스트를 선택한 채 Tab을 누르면
    // 선택 영역이 공백으로 치환되는데, 커서가 선택 길이만큼 오른쪽으로 밀렸다.
    // (선택이 없을 때는 start == end라 우연히 맞아서 눈에 안 띄었던 버그.)
    requestAnimationFrame(() => {
      textarea.selectionStart = selectionStart + 2;
      textarea.selectionEnd = selectionStart + 2;
    });
  }

  // 왼쪽 줄번호와 오른쪽 코드가 같이 스크롤되게 맞춘다.
  function handleScroll(event) {
    const gutter = event.target.previousSibling;
    if (gutter) {
      gutter.scrollTop = event.target.scrollTop;
    }
  }

  return (
    <div className="code-editor">
      <div className="code-editor__gutter" aria-hidden="true">
        {lineNumbers.map((n) => (
          <div key={n}>{n}</div>
        ))}
      </div>
      <textarea
        ref={textareaRef}
        className="code-editor__area"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        onKeyDown={handleKeyDown}
        onScroll={handleScroll}
        readOnly={readOnly}
        spellCheck={false}
        // 학습 포인트: 브라우저의 자동 대문자/맞춤법 교정이 코드를 망가뜨리므로 전부 끈다.
        autoCapitalize="off"
        autoCorrect="off"
        autoComplete="off"
        rows={lineCount}
      />
    </div>
  );
}
