// ScoreView: Rendert Demo-SVG oder PDF und legt Annotations-Layer darüber

const { useState, useEffect, useRef, useCallback } = React;

function ScoreView({ piece, annotations, tool, toolOptions, onAddPin, onAddStroke, onAddStamp, onPinClick, onMovePin, onMoveStamp, onResizeStamp, selectedPinId, selectedStampId, onStampClick, onPagesChanged, zoom = 1 }) {
  const containerRef = useRef(null);
  const [pages, setPages] = useState([]);
  const [loading, setLoading] = useState(false);
  const [hint, setHint] = useState('');

  // Lade Stück
  useEffect(() => {
    if (!piece) {
      setPages([]);
      return;
    }
    if (piece.kind === 'demo') {
      // Lade Demo-SVG
      setLoading(true);
      fetch('demo-score.svg')
        .then(r => r.text())
        .then(svgText => {
          const match = svgText.match(/viewBox="([^"]+)"/);
          let w = 1200, h = 1600;
          if (match) {
            const parts = match[1].split(/\s+/).map(Number);
            w = parts[2]; h = parts[3];
          }
          setPages([{ kind: 'svg', svg: svgText, width: w, height: h }]);
          setLoading(false);
          if (onPagesChanged) onPagesChanged(1);
        });
      return;
    }
    if (piece.kind === 'pdf' && piece.pdfFilename) {
      // PDF vom Server laden
      setLoading(true);
      loadPdfFromUrl('/api/uploads/' + piece.pdfFilename).then(loadedPages => {
        setPages(loadedPages);
        setLoading(false);
        if (onPagesChanged) onPagesChanged(loadedPages.length);
      }).catch(err => {
        console.error('PDF load failed', err);
        setLoading(false);
      });
    }
  }, [piece?.id]);

  async function loadPdfFromUrl(url) {
    if (!window.pdfjsLib) {
      throw new Error('pdfjsLib not loaded');
    }
    const pdfjs = window.pdfjsLib;
    pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@3.11.174/build/pdf.worker.min.js';
    const pdf = await pdfjs.getDocument(url).promise;
    const out = [];
    for (let i = 1; i <= pdf.numPages; i++) {
      const page = await pdf.getPage(i);
      const viewport = page.getViewport({ scale: 1.5 });
      out.push({
        kind: 'pdf',
        page,
        width: viewport.width,
        height: viewport.height,
        scale: 1.5,
      });
    }
    return out;
  }

  // Render PDF pages auf canvas elements
  useEffect(() => {
    pages.forEach((p, idx) => {
      if (p.kind === 'pdf') {
        const canvas = document.querySelector(`[data-pdf-canvas="${idx}"]`);
        if (canvas && !canvas.dataset.rendered) {
          canvas.dataset.rendered = '1';
          canvas.width = p.width;
          canvas.height = p.height;
          const ctx = canvas.getContext('2d');
          p.page.render({ canvasContext: ctx, viewport: p.page.getViewport({ scale: p.scale }) });
        }
      }
    });
  }, [pages]);

  if (!piece) {
    return null;
  }

  if (loading) {
    return (
      <div className="canvas-empty">
        <div className="spinner"></div>
        <p>Lade Noten…</p>
      </div>
    );
  }

  const showHint = (msg) => {
    setHint(msg);
    setTimeout(() => setHint(''), 2200);
  };

  return (
    <>
      {pages.map((p, pageIndex) => (
        <ScorePage
          key={pageIndex}
          page={p}
          pageIndex={pageIndex}
          tool={tool}
          toolOptions={toolOptions}
          annotations={annotations}
          onAddPin={(x, y) => { onAddPin(pageIndex, x, y); }}
          onAddStroke={(stroke) => { onAddStroke(pageIndex, stroke); }}
          onAddStamp={(x, y) => { if (onAddStamp) onAddStamp(pageIndex, x, y); }}
          onPinClick={onPinClick}
          onMovePin={onMovePin}
          onStampClick={onStampClick}
          onMoveStamp={onMoveStamp}
          onResizeStamp={onResizeStamp}
          selectedPinId={selectedPinId}
          selectedStampId={selectedStampId}
          showHint={showHint}
          zoom={zoom}
        />
      ))}
      {hint && <div className="hint">{hint}</div>}
    </>
  );
}

function ScorePage({ page, pageIndex, tool, toolOptions, annotations, onAddPin, onAddStroke, onAddStamp, onPinClick, onMovePin, onStampClick, onMoveStamp, onResizeStamp, selectedPinId, selectedStampId, showHint, zoom = 1 }) {
  const wrapRef = useRef(null);
  const overlayRef = useRef(null);
  const [drawing, setDrawing] = useState(null);
  const [draggingPin, setDraggingPin] = useState(null);
  const [draggingStamp, setDraggingStamp] = useState(null);
  const [resizingStamp, setResizingStamp] = useState(null); // { id, startY, startScale }

  const pageStamps = (annotations.stamps || []).filter(s => s.pageIndex === pageIndex);

  const pageStrokes = (annotations.strokes || []).filter(s => s.pageIndex === pageIndex);
  const pagePins = (annotations.pins || []).filter(p => p.pageIndex === pageIndex);

  const baseWidth = Math.min(page.width, 1000);
  const displayWidth = Math.round(baseWidth * zoom);
  const displayHeight = displayWidth * (page.height / page.width);

  const getRel = (e) => {
    const rect = overlayRef.current.getBoundingClientRect();
    return {
      x: (e.clientX - rect.left) / rect.width,
      y: (e.clientY - rect.top) / rect.height,
    };
  };

  const handleClick = (e) => {
    if (drawing) return;
    const { x, y } = getRel(e);
    if (tool === 'pin') {
      onAddPin(x, y);
    } else if (tool.startsWith('stamp-')) {
      onAddStamp(x, y);
    }
  };

  const handlePointerDown = (e) => {
    if (tool !== 'pen' && tool !== 'highlight' && tool !== 'eraser') return;
    e.preventDefault();
    overlayRef.current.setPointerCapture(e.pointerId);
    const { x, y } = getRel(e);
    if (tool === 'eraser') {
      eraseAt(x, y);
      setDrawing({ erasing: true });
      return;
    }
    setDrawing({
      tool,
      color: tool === 'highlight' ? toolOptions.highlightColor : toolOptions.penColor,
      width: tool === 'highlight' ? toolOptions.highlightSize : toolOptions.penSize,
      opacity: tool === 'highlight' ? 0.4 : 1,
      points: [{ x, y }],
    });
  };

  const handlePointerMove = (e) => {
    if (!drawing) return;
    const { x, y } = getRel(e);
    if (drawing.erasing) {
      eraseAt(x, y);
      return;
    }
    setDrawing(d => ({ ...d, points: [...d.points, { x, y }] }));
  };

  const handlePointerUp = (e) => {
    if (!drawing) return;
    if (!drawing.erasing && drawing.points.length > 1) {
      onAddStroke({
        id: uid(),
        tool: drawing.tool,
        color: drawing.color,
        width: drawing.width,
        opacity: drawing.opacity,
        points: drawing.points,
      });
    }
    setDrawing(null);
  };

  const eraseAt = (x, y) => {
    const threshold = 0.012;
    const toRemove = [];
    pageStrokes.forEach(s => {
      const hit = s.points.some(p => Math.hypot(p.x - x, p.y - y) < threshold);
      if (hit) toRemove.push(s.id);
    });
    if (toRemove.length) {
      window.dispatchEvent(new CustomEvent('erase-strokes', { detail: { ids: toRemove } }));
    }
  };

  const isStampTool = tool.startsWith('stamp-');
  const toolActive = tool !== 'select';
  const cursorStyle = tool === 'pen' ? 'crosshair' :
                       tool === 'highlight' ? 'crosshair' :
                       tool === 'eraser' ? 'cell' :
                       tool === 'pin' ? 'copy' :
                       isStampTool ? 'copy' : 'default';

  const pointsToPath = (points) => {
    if (points.length < 2) return '';
    let d = `M ${points[0].x * displayWidth} ${points[0].y * displayHeight}`;
    for (let i = 1; i < points.length; i++) {
      d += ` L ${points[i].x * displayWidth} ${points[i].y * displayHeight}`;
    }
    return d;
  };

  return (
    <div
      ref={wrapRef}
      className="page-wrap"
      style={{ width: displayWidth, height: displayHeight }}
    >
      <div className="page-label">Seite {pageIndex + 1}</div>

      {page.kind === 'svg' ? (
        <div
          style={{ width: '100%', height: '100%' }}
          dangerouslySetInnerHTML={{ __html: page.svg.replace(/width="\d+"/, `width="${displayWidth}"`).replace(/height="\d+"/, `height="${displayHeight}"`) }}
        />
      ) : (
        <canvas
          data-pdf-canvas={pageIndex}
          style={{ width: '100%', height: '100%', display: 'block' }}
        />
      )}

      <svg
        style={{
          position: 'absolute', top: 0, left: 0,
          width: '100%', height: '100%',
          pointerEvents: 'none',
        }}
        viewBox={`0 0 ${displayWidth} ${displayHeight}`}
      >
        {pageStrokes.map(s => (
          <path
            key={s.id}
            d={pointsToPath(s.points)}
            stroke={s.color}
            strokeWidth={s.width}
            strokeLinecap="round"
            strokeLinejoin="round"
            fill="none"
            opacity={s.opacity}
          />
        ))}
        {drawing && !drawing.erasing && drawing.points.length > 0 && (
          <path
            d={pointsToPath(drawing.points)}
            stroke={drawing.color}
            strokeWidth={drawing.width}
            strokeLinecap="round"
            strokeLinejoin="round"
            fill="none"
            opacity={drawing.opacity}
          />
        )}
      </svg>

      {pagePins.map((pin, idx) => {
        const preview = pin.text ? pin.text.split(/\s+/).slice(0, 5).join(' ') : '';
        const isDragging = draggingPin === pin.id;
        return (
          <div
            key={pin.id}
            className={`pin-group ${pin.id === selectedPinId ? 'selected' : ''} ${isDragging ? 'dragging' : ''}`}
            style={{
              left: `${pin.x * 100}%`,
              top: `${pin.y * 100}%`,
            }}
            onClick={(e) => { e.stopPropagation(); if (!isDragging) onPinClick(pin.id); }}
            onPointerDown={(e) => {
              if (tool !== 'select') return;
              e.stopPropagation();
              e.preventDefault();
              e.currentTarget.setPointerCapture(e.pointerId);
              setDraggingPin(pin.id);
            }}
            onPointerMove={(e) => {
              if (draggingPin !== pin.id) return;
              const rect = wrapRef.current.getBoundingClientRect();
              const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
              const y = Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height));
              if (onMovePin) onMovePin(pin.id, x, y);
            }}
            onPointerUp={(e) => {
              if (draggingPin !== pin.id) return;
              setDraggingPin(null);
            }}
            onPointerCancel={() => setDraggingPin(null)}
          >
            <div className="pin-marker" style={{ background: window.phaseColor(pin.phase) }}>
              <span>{pin.pinNumber || idx + 1}</span>
            </div>
            {preview && (
              <div className="pin-label">
                <span className="pin-label-phase" style={{ color: window.phaseColor(pin.phase) }}>{pin.phase}</span>
                {preview}{pin.text.split(/\s+/).length > 5 ? '…' : ''}
              </div>
            )}
          </div>
        );
      })}

      {/* Stamp-Marker */}
      {pageStamps.map(stamp => {
        const isDragging = draggingStamp === stamp.id;
        const isResizing = resizingStamp && resizingStamp.id === stamp.id;
        const iconName = stamp.type.replace('stamp-', '');
        const scale = stamp.scale || 1;
        const baseSize = 28;
        const iconSize = Math.round(baseSize * scale);
        const isSelected = stamp.id === selectedStampId;
        const stampColor = stamp.color || '#1c1917';
        const isBeat = stamp.type.startsWith('stamp-beat-');
        return (
          <div
            key={stamp.id}
            className={`stamp-marker ${isSelected ? 'selected' : ''} ${isDragging ? 'dragging' : ''} ${isBeat ? 'stamp-beat' : ''}`}
            style={{
              left: `${stamp.x * 100}%`,
              color: stampColor,
              ...(isBeat ? { borderColor: stampColor } : {}),
              top: `${stamp.y * 100}%`,
            }}
            onClick={(e) => { e.stopPropagation(); if (onStampClick) onStampClick(stamp.id); }}
            onPointerDown={(e) => {
              if (tool !== 'select') return;
              e.stopPropagation();
              e.preventDefault();
              e.currentTarget.setPointerCapture(e.pointerId);
              setDraggingStamp(stamp.id);
            }}
            onPointerMove={(e) => {
              if (draggingStamp !== stamp.id) return;
              const rect = wrapRef.current.getBoundingClientRect();
              const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
              const y = Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height));
              if (onMoveStamp) onMoveStamp(stamp.id, x, y);
            }}
            onPointerUp={() => { if (draggingStamp === stamp.id) setDraggingStamp(null); }}
            onPointerCancel={() => setDraggingStamp(null)}
          >
            <Icon name={iconName} size={iconSize} stroke={Math.max(1.5, 2.5 * scale)} />
            {isSelected && tool === 'select' && (
              <div
                className="stamp-resize-handle"
                onPointerDown={(e) => {
                  e.stopPropagation();
                  e.preventDefault();
                  e.currentTarget.setPointerCapture(e.pointerId);
                  setResizingStamp({ id: stamp.id, startY: e.clientY, startScale: scale });
                }}
                onPointerMove={(e) => {
                  if (!resizingStamp || resizingStamp.id !== stamp.id) return;
                  const dy = resizingStamp.startY - e.clientY;
                  const newScale = resizingStamp.startScale + dy / 80;
                  const clamped = Math.max(0.4, Math.min(4, newScale));
                  const delta = clamped - (stamp.scale || 1);
                  if (onResizeStamp) onResizeStamp(stamp.id, delta);
                }}
                onPointerUp={() => setResizingStamp(null)}
                onPointerCancel={() => setResizingStamp(null)}
              />
            )}
          </div>
        );
      })}

      <div
        ref={overlayRef}
        className={`page-overlay-layer ${toolActive ? 'tool-active' : ''}`}
        style={{ cursor: cursorStyle }}
        onClick={handleClick}
        onPointerDown={handlePointerDown}
        onPointerMove={handlePointerMove}
        onPointerUp={handlePointerUp}
        onPointerCancel={handlePointerUp}
      />
    </div>
  );
}

window.ScoreView = ScoreView;
