// Shared React components: ChordDiagram, Score, icons
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ===== Icons =====
const Icon = {
  Search: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>,
  Plus: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 5v14M5 12h14"/></svg>,
  Star: (p) => <svg viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" {...p}><path d="m12 3 2.7 6 6.3.6-4.8 4.3 1.4 6.3L12 17l-5.6 3.2 1.4-6.3L3 9.6 9.3 9z"/></svg>,
  StarOutline: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round" {...p}><path d="m12 3 2.7 6 6.3.6-4.8 4.3 1.4 6.3L12 17l-5.6 3.2 1.4-6.3L3 9.6 9.3 9z"/></svg>,
  Back: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m15 18-6-6 6-6"/></svg>,
  Edit: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5z"/></svg>,
  Trash: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>,
  Close: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M18 6 6 18M6 6l12 12"/></svg>,
  Folder: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>,
  More: (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/></svg>,
  Music: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>,
  Minus: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" {...p}><path d="M5 12h14"/></svg>,
  Reset: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/></svg>,
};

// ===== ChordDiagram =====
// strings displayed left to right: G, C, E, A
// `size` controls overall scale.
function ChordDiagram({ name, size = 1 }) {
  const def = window.CHORDS[name];
  // Standard: 4 strings, 4 frets shown
  const STRINGS = 4;
  const FRETS = 4;
  const cellW = 6 * size;
  const cellH = 6 * size;
  const padX = 3 * size;
  const padTop = 3 * size; // for nut/open markers
  const w = padX * 2 + (STRINGS - 1) * cellW;
  const h = padTop + FRETS * cellH + 2 * size;

  if (!def) {
    // Unknown chord — render a faint grid placeholder
    return (
      <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} aria-label={`${name} (unknown)`}>
        <rect x={padX} y={padTop} width={(STRINGS - 1) * cellW} height={FRETS * cellH} fill="none" stroke="#d4d4d8" strokeWidth="0.6" strokeDasharray="2 2"/>
      </svg>
    );
  }

  const { frets, barre, baseFret = 1 } = def;
  const gridX = padX;
  const gridY = padTop;
  const gridW = (STRINGS - 1) * cellW;
  const gridH = FRETS * cellH;

  // Lines: 4 strings (vertical), 5 fret lines (horizontal)
  const stringLines = [];
  for (let i = 0; i < STRINGS; i++) {
    stringLines.push(<line key={`s${i}`} x1={gridX + i * cellW} y1={gridY} x2={gridX + i * cellW} y2={gridY + gridH} stroke="#18181b" strokeWidth="0.6"/>);
  }
  const fretLines = [];
  for (let i = 0; i <= FRETS; i++) {
    const y = gridY + i * cellH;
    fretLines.push(<line key={`f${i}`} x1={gridX} y1={y} x2={gridX + gridW} y2={y} stroke="#18181b" strokeWidth={i === 0 ? 1.4 : 0.6}/>);
  }

  // Dots
  const dots = [];
  frets.forEach((fret, stringIdx) => {
    const x = gridX + stringIdx * cellW;
    if (fret === 0) {
      // open: small circle above nut
      // Skip drawing 'O' for cleaner look — matches reference image
    } else if (fret > 0) {
      const fretRow = fret - baseFret + 1; // 1-based fret position within visible window
      if (fretRow >= 1 && fretRow <= FRETS) {
        const y = gridY + (fretRow - 0.5) * cellH;
        dots.push(<circle key={`d${stringIdx}`} cx={x} cy={y} r={1.8 * size} fill="#18181b"/>);
      }
    }
  });

  // Barre (horizontal line/rect across multiple strings)
  let barreEl = null;
  if (barre) {
    const { fret, from, to } = barre;
    const fretRow = fret - baseFret + 1;
    if (fretRow >= 1 && fretRow <= FRETS) {
      const y = gridY + (fretRow - 0.5) * cellH;
      const x1 = gridX + from * cellW;
      const x2 = gridX + to * cellW;
      barreEl = <rect x={x1 - 1.8 * size} y={y - 1.6 * size} width={(x2 - x1) + 3.6 * size} height={3.2 * size} rx={1.6 * size} fill="#18181b"/>;
    }
  }

  // Base fret indicator (e.g., '3fr')
  let baseFretLabel = null;
  if (baseFret > 1) {
    baseFretLabel = <text x={gridX + gridW + 1.5 * size} y={gridY + cellH * 0.7} fontSize={4 * size} fill="#52525b" fontFamily="Pretendard, sans-serif">{baseFret}fr</text>;
  }

  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} aria-label={name} style={{ display: 'block', flexShrink: 0 }}>
      {fretLines}
      {stringLines}
      {barreEl}
      {dots}
      {baseFretLabel}
    </svg>
  );
}

// ===== Time signature =====
function TimeSig({ value }) {
  if (!value) return null;
  const [num, den] = value.split('/');
  return (
    <span className="time-sig">
      <span>{num}</span>
      <span>{den}</span>
    </span>
  );
}

// ===== Sheet renderer =====
// Props:
//   chords: string[][]  — array of measures, each measure is an array of chord names
//   verses: string[][]  — array of verses, each verse is an array of lyric strings per measure
//   timeSignature: e.g. "4/4"
//   bars: { [measureIndex]: { left?: 'repeat-start' | 'double', right?: 'repeat-end' | 'final' | 'double', volta?: '1'|'2' } }
//   onBarClick?: (measureIndex) => void
//   transposeBy?: number
function Sheet({ chords, verses, timeSignature, bars = {}, onBarClick, transposeBy = 0 }) {
  const totalMeasures = chords.length;

  // Responsive: 2 measures/line on mobile, 4 on larger screens
  const [perLine, setPerLine] = useState(() => (typeof window !== 'undefined' && window.matchMedia('(max-width: 600px)').matches) ? 2 : 4);
  useEffect(() => {
    const mql = window.matchMedia('(max-width: 600px)');
    const onChange = (e) => setPerLine(e.matches ? 2 : 4);
    mql.addEventListener ? mql.addEventListener('change', onChange) : mql.addListener(onChange);
    return () => { mql.removeEventListener ? mql.removeEventListener('change', onChange) : mql.removeListener(onChange); };
  }, []);

  if (totalMeasures === 0) return null;

  // Chunk into lines of `perLine` measures
  const lines = [];
  for (let i = 0; i < totalMeasures; i += perLine) {
    lines.push({ start: i, end: Math.min(i + perLine, totalMeasures) });
  }

  return (
    <div className="sheet">
      {lines.map((line, lineIdx) => {
        const measureCount = line.end - line.start;
        // Pad to `perLine` measures with empty slots so grid stays even
        const padded = Array(perLine).fill(null).map((_, i) => {
          const idx = line.start + i;
          if (i < measureCount) return { idx, chords: chords[idx], present: true };
          return { idx: -1, chords: [], present: false };
        });

        return (
          <div className="sheet-line" key={lineIdx} style={{ gridTemplateColumns: `repeat(${perLine}, 1fr)` }}>
            {padded.map((m, colIdx) => {
              if (!m.present) {
                // Empty pad
                return <div key={colIdx} style={{ visibility: 'hidden' }} className="measure" />;
              }
              const isFirstMeasureEver = m.idx === 0;
              const isLastMeasureEver = m.idx === totalMeasures - 1;
              const barInfo = bars[m.idx] || {};
              const measureChords = m.chords;

              return (
                <div
                  key={colIdx}
                  className="measure"
                  data-bar-left={barInfo.left || (isFirstMeasureEver ? 'none' : 'normal')}
                  data-bar-right={barInfo.right}
                  data-is-final={(isLastMeasureEver && !barInfo.right) ? 'true' : undefined}
                  data-volta={barInfo.volta}
                >
                  {barInfo.volta && <div className="volta">{barInfo.volta}.</div>}
                  {/* Barline click target — only handles the LEFT barline of this measure */}
                  <button
                    className="barline-hit"
                    aria-label="마디 시작 기호 변경"
                    onClick={(e) => { e.stopPropagation(); onBarClick && onBarClick(m.idx, 'left', e.currentTarget); }}
                    style={{
                      position: 'absolute', left: -8, top: 0, bottom: 0, width: 16, background: 'transparent',
                      cursor: 'pointer', zIndex: 2, padding: 0, border: 0
                    }}
                  />
                  {/* Right barline (only for last col of line or final measure) */}
                  {colIdx === perLine - 1 || m.idx === totalMeasures - 1 ? (

                    <button
                      className="barline-hit"
                      aria-label="마디 끝 기호 변경"
                      onClick={(e) => { e.stopPropagation(); onBarClick && onBarClick(m.idx, 'right', e.currentTarget); }}
                      style={{
                        position: 'absolute', right: -8, top: 0, bottom: 0, width: 16, background: 'transparent',
                        cursor: 'pointer', zIndex: 2, padding: 0, border: 0
                      }}
                    />
                  ) : null}

                  <div className="measure-top">
                    {isFirstMeasureEver && timeSignature && <TimeSig value={timeSignature}/>}
                    {measureChords.map((rawCh, ci) => {
                      const ch = transposeBy ? window.transposeChord(rawCh, transposeBy) : rawCh;
                      return (
                        <span className="chord-cluster" key={ci}>
                          <span className="chord-name">{ch}</span>
                          <ChordDiagram name={ch} size={1.2}/>
                        </span>
                      );
                    })}
                  </div>

                  <div className="measure-bottom">
                    {verses.map((verse, vi) => {
                      const text = verse[m.idx] || '';
                      return (
                        <div key={vi} className={`lyric-line ${text ? '' : 'placeholder'}`}>
                          {text || (vi === 0 ? '·' : '\u00A0')}
                        </div>
                      );
                    })}
                  </div>
                </div>
              );
            })}
          </div>
        );
      })}
    </div>
  );
}

// ===== Bar symbol popover =====
function BarPopover({ anchorRect, side, value, onChange, onClose }) {
  const ref = useRef(null);
  useEffect(() => {
    const onDoc = (e) => {
      if (ref.current && !ref.current.contains(e.target)) onClose();
    };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [onClose]);

  if (!anchorRect) return null;
  const top = anchorRect.bottom + 8 + window.scrollY;
  const left = Math.min(anchorRect.left + window.scrollX - 60, window.innerWidth - 200);

  const leftOptions = [
    { val: undefined, label: '일반', svg: <BarGlyph kind="normal"/> },
    { val: 'repeat-start', label: '반복 시작', svg: <BarGlyph kind="repeat-start"/> },
    { val: 'double', label: '겹세로', svg: <BarGlyph kind="double"/> },
  ];
  const rightOptions = [
    { val: undefined, label: '일반', svg: <BarGlyph kind="normal"/> },
    { val: 'repeat-end', label: '반복 끝', svg: <BarGlyph kind="repeat-end"/> },
    { val: 'final', label: '마지막', svg: <BarGlyph kind="final"/> },
    { val: 'double', label: '겹세로', svg: <BarGlyph kind="double"/> },
  ];
  const options = side === 'left' ? leftOptions : rightOptions;
  const title = side === 'left' ? '왼쪽 마디선' : '오른쪽 마디선';

  return (
    <div ref={ref} className="bar-popover" style={{ top, left }} onClick={(e) => e.stopPropagation()}>
      <div className="bar-label">{title}</div>
      {options.map((opt, i) => (
        <button
          key={i}
          className={value === opt.val ? 'is-active' : ''}
          onClick={() => { onChange(opt.val); onClose(); }}
          title={opt.label}
        >
          {opt.svg}
        </button>
      ))}
    </div>
  );
}

function BarGlyph({ kind }) {
  const stroke = '#18181b';
  switch (kind) {
    case 'normal':
      return <svg width="20" height="28" viewBox="0 0 20 28"><line x1="10" y1="2" x2="10" y2="26" stroke={stroke} strokeWidth="1.5"/></svg>;
    case 'double':
      return <svg width="20" height="28" viewBox="0 0 20 28"><line x1="7" y1="2" x2="7" y2="26" stroke={stroke} strokeWidth="1.5"/><line x1="13" y1="2" x2="13" y2="26" stroke={stroke} strokeWidth="1.5"/></svg>;
    case 'repeat-start':
      return <svg width="20" height="28" viewBox="0 0 20 28">
        <rect x="6" y="2" width="3" height="24" fill={stroke}/>
        <line x1="11" y1="2" x2="11" y2="26" stroke={stroke} strokeWidth="1"/>
        <circle cx="15" cy="11" r="1.4" fill={stroke}/>
        <circle cx="15" cy="17" r="1.4" fill={stroke}/>
      </svg>;
    case 'repeat-end':
      return <svg width="20" height="28" viewBox="0 0 20 28">
        <circle cx="5" cy="11" r="1.4" fill={stroke}/>
        <circle cx="5" cy="17" r="1.4" fill={stroke}/>
        <line x1="9" y1="2" x2="9" y2="26" stroke={stroke} strokeWidth="1"/>
        <rect x="11" y="2" width="3" height="24" fill={stroke}/>
      </svg>;
    case 'final':
      return <svg width="20" height="28" viewBox="0 0 20 28">
        <line x1="9" y1="2" x2="9" y2="26" stroke={stroke} strokeWidth="1"/>
        <rect x="11" y="2" width="3" height="24" fill={stroke}/>
      </svg>;
    default: return null;
  }
}

// ===== Parsers =====
// chords: "F,G/Am,D7/F/Am" → [["F","G"], ["Am","D7"], ["F"], ["Am"]]
function parseChords(input) {
  if (!input) return [];
  return input.split('/').map(m => m.split(',').map(c => c.trim()).filter(Boolean));
}
function stringifyChords(chords) {
  return chords.map(m => m.join(',')).join('/');
}
// lyrics: "바람에/지는 계절엔/..." → ["바람에", "지는 계절엔", ...]
function parseLyrics(input) {
  if (!input) return [];
  return input.split('/').map(s => s.trim());
}
function stringifyLyrics(arr) {
  return (arr || []).join('/');
}

Object.assign(window, { Icon, ChordDiagram, Sheet, BarPopover, BarGlyph, TimeSig, parseChords, parseLyrics, stringifyChords, stringifyLyrics });
