// Hauptkomponente - Routing: Auth → Dashboard → Editor (API-basiert)

const { useReducer, useEffect: useEffectMain, useState: useStateMain, useRef: useRefMain } = React;

function reducer(state, action) {
  switch (action.type) {
    case 'select-piece':
      return { ...state, activePieceId: action.id };
    case 'add-piece': {
      const pieces = [...state.pieces, action.piece];
      const annotations = { ...state.annotations, [action.piece.id]: { strokes: [], pins: [], checklist: {}, rehearsals: [] } };
      return { ...state, pieces, annotations, activePieceId: action.piece.id };
    }
    case 'delete-piece': {
      const pieces = state.pieces.filter(p => p.id !== action.id);
      const annotations = { ...state.annotations };
      delete annotations[action.id];
      const activePieceId = state.activePieceId === action.id ? (pieces[0]?.id || null) : state.activePieceId;
      return { ...state, pieces, annotations, activePieceId };
    }
    case 'rename-piece': {
      const pieces = state.pieces.map(p => p.id === action.id ? { ...p, title: action.title } : p);
      return { ...state, pieces };
    }
    case 'set-tab': return { ...state, activeTab: action.tab };
    case 'set-filter': return { ...state, activePhaseFilter: action.phase };
    case 'add-pin': {
      const pid = state.activePieceId;
      const ann = state.annotations[pid] || { strokes: [], pins: [], checklist: {}, rehearsals: [] };
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, pins: [...ann.pins, action.pin] } } };
    }
    case 'update-pin': {
      const pid = state.activePieceId; const ann = state.annotations[pid];
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, pins: ann.pins.map(p => p.id === action.pin.id ? action.pin : p) } } };
    }
    case 'delete-pin': {
      const pid = state.activePieceId; const ann = state.annotations[pid];
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, pins: ann.pins.filter(p => p.id !== action.id) } } };
    }
    case 'add-stroke': {
      const pid = state.activePieceId;
      const ann = state.annotations[pid] || { strokes: [], pins: [], checklist: {}, rehearsals: [] };
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, strokes: [...ann.strokes, { ...action.stroke, pageIndex: action.pageIndex }] } } };
    }
    case 'erase-strokes': {
      const pid = state.activePieceId; const ann = state.annotations[pid];
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, strokes: ann.strokes.filter(s => !action.ids.includes(s.id)) } } };
    }
    case 'add-stamp': {
      const pid = state.activePieceId;
      const ann = state.annotations[pid] || { strokes: [], pins: [], stamps: [], checklist: {}, rehearsals: [] };
      const stamps = [...(ann.stamps || []), action.stamp];
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, stamps } } };
    }
    case 'update-stamp': {
      const pid = state.activePieceId; const ann = state.annotations[pid];
      const stamps = (ann.stamps || []).map(s => s.id === action.stamp.id ? action.stamp : s);
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, stamps } } };
    }
    case 'delete-stamp': {
      const pid = state.activePieceId; const ann = state.annotations[pid];
      const stamps = (ann.stamps || []).filter(s => s.id !== action.id);
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, stamps } } };
    }
    case 'toggle-check': {
      const pid = state.activePieceId; const ann = state.annotations[pid];
      const checklist = { ...ann.checklist, [action.key]: !ann.checklist[action.key] };
      if (checklist[action.key]) delete checklist[action.key + '-na'];
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, checklist } } };
    }
    case 'toggle-na': {
      const pid = state.activePieceId; const ann = state.annotations[pid];
      const naKey = action.key + '-na';
      const checklist = { ...ann.checklist };
      if (checklist[naKey]) {
        delete checklist[naKey];
      } else {
        checklist[naKey] = true;
        delete checklist[action.key];
      }
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, checklist } } };
    }
    case 'save-rehearsal': {
      const pid = state.activePieceId; const ann = state.annotations[pid];
      const exists = ann.rehearsals.some(r => r.id === action.rehearsal.id);
      const r = { ...action.rehearsal }; delete r._new;
      const rehearsals = exists ? ann.rehearsals.map(x => x.id === r.id ? r : x) : [...ann.rehearsals, r];
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, rehearsals } } };
    }
    case 'delete-rehearsal': {
      const pid = state.activePieceId; const ann = state.annotations[pid];
      return { ...state, annotations: { ...state.annotations, [pid]: { ...ann, rehearsals: ann.rehearsals.filter(r => r.id !== action.id) } } };
    }
    case 'restore-drawing': {
      const ann = state.annotations[action.pieceId];
      if (!ann) return state;
      return { ...state, annotations: { ...state.annotations, [action.pieceId]: { ...ann, strokes: action.strokes, stamps: action.stamps } } };
    }
    case 'replace-state': return action.state;
    default: return state;
  }
}

const emptyState = {
  pieces: [],
  activePieceId: null,
  activeTab: 'comments',
  activePhaseFilter: null,
  annotations: {},
};

function App() {
  const [user, setUser] = useStateMain(null);
  const [appLoading, setAppLoading] = useStateMain(true);
  const [view, setView] = useStateMain('dashboard');
  const [state, dispatch] = useReducer(reducer, emptyState);
  const [tool, setTool] = useStateMain('select');
  const [toolOptions, setToolOptions] = useStateMain({
    penColor: '#1c1917', penSize: 2, highlightColor: '#fbbf24', highlightSize: 14,
  });
  const [editingPin, setEditingPin] = useStateMain(null);
  const [selectedPinId, setSelectedPinId] = useStateMain(null);
  const [selectedStampId, setSelectedStampId] = useStateMain(null);
  const [exporting, setExporting] = useStateMain(false);
  const [zoom, setZoom] = useStateMain(1);

  // Refs für Debounce + Zoom
  const canvasAreaRef = useRefMain(null);
  const saveTimer = useRefMain(null);
  const stampDragUndoPushed = useRefMain(null);
  const stampResizeUndoPushed = useRefMain(null);

  // --- Undo-Stack (Strokes + Stamps) ---
  const undoStack = useRefMain([]);
  const MAX_UNDO = 50;

  const pushUndo = () => {
    if (!state.activePieceId) return;
    const ann = state.annotations[state.activePieceId];
    if (!ann) return;
    const snapshot = {
      pieceId: state.activePieceId,
      strokes: JSON.parse(JSON.stringify(ann.strokes || [])),
      stamps: JSON.parse(JSON.stringify(ann.stamps || [])),
    };
    undoStack.current = [...undoStack.current.slice(-(MAX_UNDO - 1)), snapshot];
  };

  const performUndo = () => {
    if (undoStack.current.length === 0) return;
    const snapshot = undoStack.current.pop();
    const ann = state.annotations[snapshot.pieceId];
    if (!ann) return;
    dispatch({
      type: 'restore-drawing',
      pieceId: snapshot.pieceId,
      strokes: snapshot.strokes,
      stamps: snapshot.stamps,
    });
  };
  const renameTimer = useRefMain(null);

  // --- Init: Session prüfen ---
  useEffectMain(() => {
    window.apiCurrentUser().then(async (u) => {
      if (!u) { setAppLoading(false); return; }
      setUser(u);
      try {
        const data = await window.apiLoadState();
        if (data && data.pieces) {
          dispatch({
            type: 'replace-state',
            state: {
              pieces: data.pieces,
              activePieceId: data.pieces[0]?.id || null,
              activeTab: 'comments',
              activePhaseFilter: null,
              annotations: data.annotations || {},
            },
          });
        }
      } catch (err) {
        console.error('State laden fehlgeschlagen:', err);
      }
      setAppLoading(false);
    }).catch(() => setAppLoading(false));
  }, []);

  // --- Debounced Save: Annotations des aktiven Stücks ---
  useEffectMain(() => {
    if (!user || !state.activePieceId) return;
    const ann = state.annotations[state.activePieceId];
    if (!ann) return;

    clearTimeout(saveTimer.current);
    saveTimer.current = setTimeout(() => {
      window.apiSaveAnnotations(state.activePieceId, ann).catch(console.error);
    }, 800);

    return () => clearTimeout(saveTimer.current);
  }, [state.annotations, state.activePieceId]);

  // --- Keyboard shortcuts (nur im Editor) ---
  useEffectMain(() => {
    if (view !== 'editor') return;
    const handler = (e) => {
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
      if (e.key === 'v') setTool('select');
      else if (e.key === 'c') setTool('pin');
      else if (e.key === 'p') setTool('pen');
      else if (e.key === 'h') setTool('highlight');
      else if (e.key === 'e') setTool('eraser');
      else if (e.key === 'Escape') { setTool('select'); setEditingPin(null); setSelectedStampId(null); }
      else if ((e.key === 'Delete' || e.key === 'Backspace') && selectedStampId) {
        e.preventDefault();
        pushUndo();
        dispatch({ type: 'delete-stamp', id: selectedStampId });
        setSelectedStampId(null);
      }
      else if ((e.key === 'z' || e.key === 'Z') && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        performUndo();
      }
      else if ((e.key === '+' || e.key === '=') && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        setZoom(z => Math.min(3, z + 0.1));
      }
      else if (e.key === '-' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        setZoom(z => Math.max(0.3, z - 0.1));
      }
      else if (e.key === '0' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        setZoom(1);
      }
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, [view, selectedStampId]);

  // --- Erase-Strokes custom event ---
  useEffectMain(() => {
    const handler = (e) => { pushUndo(); dispatch({ type: 'erase-strokes', ids: e.detail.ids }); };
    window.addEventListener('erase-strokes', handler);
    return () => window.removeEventListener('erase-strokes', handler);
  }, []);

  // Ctrl+Wheel Zoom auf canvas-area
  useEffectMain(() => {
    const el = canvasAreaRef.current;
    if (!el) return;
    const handler = (e) => {
      if (e.ctrlKey || e.metaKey) {
        e.preventDefault();
        setZoom(z => Math.min(3, Math.max(0.3, z - e.deltaY * 0.001)));
      }
    };
    el.addEventListener('wheel', handler, { passive: false });
    return () => el.removeEventListener('wheel', handler);
  });

  // --- API-Dispatch: lokaler dispatch + API-Seiteneffekte ---
  const apiDispatch = (action) => {
    dispatch(action);

    switch (action.type) {
      case 'delete-piece':
        window.apiDeletePiece(action.id).catch(console.error);
        break;
      case 'rename-piece':
        clearTimeout(renameTimer.current);
        renameTimer.current = setTimeout(() => {
          window.apiUpdatePiece(action.id, { title: action.title }).catch(console.error);
        }, 600);
        break;
    }
  };

  // --- Auth Callbacks ---
  const onAuthenticated = async (u) => {
    setUser(u);
    try {
      const data = await window.apiLoadState();
      if (data && data.pieces) {
        dispatch({
          type: 'replace-state',
          state: {
            pieces: data.pieces,
            activePieceId: data.pieces[0]?.id || null,
            activeTab: 'comments',
            activePhaseFilter: null,
            annotations: data.annotations || {},
          },
        });
      }
    } catch (err) {
      console.error('State laden nach Login fehlgeschlagen:', err);
    }
    setView('dashboard');
  };

  const onLogout = async () => {
    await window.apiLogout();
    setUser(null);
    dispatch({ type: 'replace-state', state: emptyState });
    setView('dashboard');
  };

  // --- Upload PDF ---
  const onUploadPdf = async (file) => {
    try {
      const result = await window.apiUploadPiece(file);
      if (result.ok && result.piece) {
        dispatch({ type: 'add-piece', piece: result.piece });
        setView('editor');
      }
    } catch (err) {
      console.error('Upload fehlgeschlagen:', err);
      alert('PDF-Upload fehlgeschlagen.');
    }
  };

  // --- Import ZIP ---
  const onImportZip = async (file) => {
    try {
      const { piece, annotations } = await window.importPieceZip(file);
      dispatch({ type: 'add-piece', piece });
      dispatch({ type: 'replace-state', state: {
        ...state,
        pieces: [...state.pieces, piece],
        annotations: { ...state.annotations, [piece.id]: annotations },
        activePieceId: piece.id,
      }});
    } catch (err) {
      console.error('Import fehlgeschlagen:', err);
      alert('Import fehlgeschlagen: ' + err.message);
    }
  };

  // --- Loading Screen ---
  if (appLoading) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh', flexDirection: 'column', gap: 12 }}>
        <div className="spinner" />
        <span style={{ color: 'var(--text-soft)', fontSize: 13 }}>Lade…</span>
      </div>
    );
  }

  // --- Auth Screen ---
  if (!user) {
    return <AuthScreen onAuthenticated={onAuthenticated} />;
  }

  const piece = state.pieces.find(p => p.id === state.activePieceId);
  const ann = state.annotations[state.activePieceId] || { strokes: [], pins: [], checklist: {}, rehearsals: [] };

  const onAddPin = (pageIndex, x, y) => {
    setEditingPin({
      id: window.uid(), pageIndex, x, y,
      phase: 'V3', subtags: [], text: '',
      createdAt: Date.now(), _new: true,
    });
  };

  const saveNewPin = (draft) => {
    const clean = { ...draft }; delete clean._new;
    if (draft._new) dispatch({ type: 'add-pin', pin: clean });
    else dispatch({ type: 'update-pin', pin: clean });
    setEditingPin(null);
    setSelectedPinId(clean.id);
  };

  const onPinClick = (pinId) => {
    setSelectedPinId(pinId);
    setTimeout(() => {
      const el = document.querySelector(`[data-comment-id="${pinId}"]`);
      if (el) el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    }, 50);
  };

  const onEditPin = (pin) => setEditingPin({ ...pin });
  const onAddStroke = (pageIndex, stroke) => { pushUndo(); dispatch({ type: 'add-stroke', stroke, pageIndex }); };
  const onMovePin = (pinId, x, y) => {
    const pin = ann.pins.find(p => p.id === pinId);
    if (pin) dispatch({ type: 'update-pin', pin: { ...pin, x, y } });
  };

  const onAddStamp = (pageIndex, x, y) => {
    pushUndo();
    const isLarge = tool.startsWith('stamp-beat-');
    const stamp = { id: window.uid(), pageIndex, x, y, type: tool, scale: isLarge ? 1.5 : 1, color: toolOptions.penColor, createdAt: Date.now() };
    dispatch({ type: 'add-stamp', stamp });
    setSelectedStampId(stamp.id);
    setTool('select');
  };
  const onMoveStamp = (stampId, x, y) => {
    if (stampDragUndoPushed.current !== stampId) { pushUndo(); stampDragUndoPushed.current = stampId; }
    const stamp = (ann.stamps || []).find(s => s.id === stampId);
    if (stamp) dispatch({ type: 'update-stamp', stamp: { ...stamp, x, y } });
  };
  const onStampClick = (stampId) => {
    stampDragUndoPushed.current = null;
    stampResizeUndoPushed.current = null;
    setSelectedStampId(stampId);
    setSelectedPinId(null);
  };
  const onResizeStamp = (stampId, delta) => {
    if (stampResizeUndoPushed.current !== stampId) { pushUndo(); stampResizeUndoPushed.current = stampId; }
    const stamp = (ann.stamps || []).find(s => s.id === stampId);
    if (!stamp) return;
    const newScale = Math.max(0.4, Math.min(4, (stamp.scale || 1) + delta));
    dispatch({ type: 'update-stamp', stamp: { ...stamp, scale: newScale } });
  };

  const onOpenPiece = (id) => {
    apiDispatch({ type: 'select-piece', id });
    setView('editor');
  };

  const bmcButton = (
    <a href="https://buymeacoffee.com/kalikoer" target="_blank" rel="noopener noreferrer" className="bmc-fixed" title="Buy me a coffee">
      ☕ Buy me a coffee
    </a>
  );

  // --- Admin ---
  if (view === 'admin' && user?.email === 'johannes.golda@posteo.de') {
    return <AdminPanel user={user} onBack={() => setView('dashboard')} />;
  }

  // --- Dashboard ---
  if (view === 'dashboard') {
    return (
      <>
        <Dashboard
          user={user}
          state={state}
          dispatch={apiDispatch}
          onOpenPiece={onOpenPiece}
          onLogout={onLogout}
          onUploadPdf={onUploadPdf}
          onImportZip={onImportZip}
          onOpenAdmin={() => setView('admin')}
        />
        {bmcButton}
      </>
    );
  }

  // --- Editor View ---
  const totalPins = ann.pins.length;

  return (
    <div className="app">
      <header className="topbar">
        <button className="topbar-back" onClick={() => setView('dashboard')} title="Zurück zur Übersicht">
          ← Übersicht
        </button>
        <div className="topbar-divider" />
        <div className="topbar-brand">
          <a href="https://kalikoer.com" target="_blank" rel="noopener noreferrer"><img src="kalikoer-logo.png" alt="Kalikoer" className="topbar-logo" /></a>
        </div>
        {piece ? (
          <input
            className="topbar-piece-name"
            value={piece.title}
            onChange={e => apiDispatch({ type: 'rename-piece', id: piece.id, title: e.target.value })}
            placeholder="Titel des Stücks"
          />
        ) : (
          <span style={{ color: 'var(--text-soft)' }}>Kein Stück gewählt</span>
        )}
        <div className="topbar-spacer" />
        {piece && (
          <button
            className="topbar-action"
            disabled={exporting}
            onClick={async () => {
              setExporting(true);
              try {
                await window.exportAnalysisPdf(piece, ann);
              } catch (err) {
                console.error('Export fehlgeschlagen:', err);
                alert('PDF-Export fehlgeschlagen.');
              }
              setExporting(false);
            }}
          >
            <Icon name="download" size={15} />
            {exporting ? 'Exportiere…' : 'PDF Export'}
          </button>
        )}
        <div className="topbar-divider" />
        <span style={{ fontSize: 12, color: 'var(--text-soft)' }}>
          {totalPins} Kommentar{totalPins === 1 ? '' : 'e'} · gespeichert
        </span>
        <span style={{ fontSize: 12, color: 'var(--text-soft)' }}>· {user.name}</span>
      </header>

      <SidebarLeft state={state} dispatch={apiDispatch} onUploadPdf={onUploadPdf} />

      <main className="canvas-area" ref={canvasAreaRef}>
        {!piece && (
          <div className="canvas-empty">
            <div className="canvas-empty-icon"><Icon name="music" size={32} /></div>
            <h2>Kein Stück geöffnet</h2>
            <p>Wähle ein Stück aus der Übersicht oder lade ein PDF hoch.</p>
            <button className="upload-btn secondary" onClick={() => setView('dashboard')}>Zur Übersicht</button>
          </div>
        )}
        {piece && <Toolbar tool={tool} setTool={setTool} toolOptions={toolOptions} setToolOptions={setToolOptions} onUndo={performUndo} canUndo={undoStack.current.length > 0} zoom={zoom} setZoom={setZoom} />}
        {piece && (
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: '100%' }}>
            <ScoreView
              piece={piece} annotations={ann}
              tool={tool} toolOptions={toolOptions}
              onAddPin={onAddPin} onAddStroke={onAddStroke} onAddStamp={onAddStamp}
              onPinClick={onPinClick} onMovePin={onMovePin}
              onStampClick={onStampClick} onMoveStamp={onMoveStamp} onResizeStamp={onResizeStamp}
              selectedPinId={selectedPinId} selectedStampId={selectedStampId}
              zoom={zoom}
            />
          </div>
        )}
      </main>

      <SidebarRight
        state={state} dispatch={apiDispatch}
        onEditPin={onEditPin} onSelectPin={onPinClick}
        selectedPinId={selectedPinId}
      />

      {editingPin && (
        <CommentEditor
          pin={editingPin}
          onSave={saveNewPin}
          onDelete={() => {
            if (!editingPin._new) dispatch({ type: 'delete-pin', id: editingPin.id });
            setEditingPin(null);
          }}
          onClose={() => setEditingPin(null)}
        />
      )}
      {bmcButton}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
