/* organizer-app.jsx — Root component + auth + page routing + data fetching
 * React 18 · in-browser Babel · no build step
 * Deps: window.AdminSession, window.AdminApi, window.ORG_NAV,
 *        window.OrgSidebar, window.OrgTopbar, window.OrgDocFooter,
 *        window.OrgLoginScreen, window.OrgSessionsDashboard,
 *        window.OrgOverviewPage, window.OrgMonitorPage, window.OrgPlaceholderPage,
 *        window.OrgQuestionBankPage, window.OrgContentLibraryPage,
 *        window.OrgSettingsPage, window.OrgProctorPage,
 *        window.OrgCreateWizard
 */

// ---------------------------------------------------------------------------
// OrganizerApp — Root component with auth gate + page router
// ---------------------------------------------------------------------------
window.OrganizerApp = function OrganizerApp() {
  const [authState, setAuthState] = React.useState('checking'); // 'checking' | 'login' | 'authenticated'
  const [admin, setAdmin]         = React.useState(null);
  const [activePage, setActivePage] = React.useState('sessions');
  const [toast, setToast]         = React.useState(null);

  // --- Data state (fetched after auth) ---
  const [games, setGames]         = React.useState([]);
  const [metrics, setMetrics]     = React.useState(null);
  const [selectedGameId, setSelectedGameId] = React.useState(null);
  const [gameDetail, setGameDetail] = React.useState(null); // leaderboard, phase, players for selected game
  const [loading, setLoading]     = React.useState(false);
  const [editingEvent, setEditingEvent] = React.useState(null);
  const [selectedEventType, setSelectedEventType] = React.useState(null); // tech-day | clinic | connect | custom | null

  // Resolve event_type for the currently-selected game (used to branch Monitor view)
  React.useEffect(function() {
    if (!gameDetail || !gameDetail.game || !gameDetail.game.event_id) {
      setSelectedEventType(null);
      return;
    }
    var eid = gameDetail.game.event_id;
    AdminApi.getEvent(eid).then(function(ev) {
      var cfg = ev && ev.config;
      if (typeof cfg === 'string') { try { cfg = JSON.parse(cfg); } catch(e) { cfg = {}; } }
      cfg = cfg || {};
      setSelectedEventType(cfg.event_type || null);
    }).catch(function() { setSelectedEventType(null); });
  }, [gameDetail && gameDetail.game && gameDetail.game.event_id]);

  // --- Toast helper ---
  const showToast = React.useCallback(function(msg, type) {
    setToast({ msg: msg, type: type || 'info' });
    setTimeout(function() { setToast(null); }, 4000);
  }, []);

  // --- Auth: validate stored token on mount ---
  React.useEffect(function() {
    if (!AdminSession.isLoggedIn()) {
      setAuthState('login');
      return;
    }
    AdminApi.me()
      .then(function(data) {
        setAdmin(data);
        AdminSession.setAdmin(data);
        setAuthState('authenticated');
      })
      .catch(function() {
        AdminSession.clear();
        setAuthState('login');
      });
  }, []);

  // --- Listen for session expiry (401 from AdminApi) ---
  React.useEffect(function() {
    function onExpired() {
      setAuthState('login');
      setAdmin(null);
      showToast('Session expired — please log in again', 'error');
    }
    window.addEventListener('admin-session-expired', onExpired);
    return function() { window.removeEventListener('admin-session-expired', onExpired); };
  }, [showToast]);

  // --- Login handler ---
  function handleLogin(email, password) {
    setLoading(true);
    return AdminApi.login(email, password)
      .then(function(data) {
        AdminSession.setToken(data.token);
        AdminSession.setAdmin(data.admin);
        setAdmin(data.admin);
        setAuthState('authenticated');
        showToast('Welcome, ' + data.admin.display_name, 'ok');
      })
      .catch(function(err) {
        showToast(err.message || 'Login failed', 'error');
      })
      .finally(function() { setLoading(false); });
  }

  // --- Logout handler ---
  function handleLogout() {
    AdminApi.logout().catch(function() {});
    AdminSession.clear();
    setAdmin(null);
    setAuthState('login');
    setGames([]);
    setMetrics(null);
    setSelectedGameId(null);
    setGameDetail(null);
  }

  // --- Fetch games + metrics when authenticated ---
  React.useEffect(function() {
    if (authState !== 'authenticated') return;
    refreshGames();
    refreshMetrics();
    // Handle URL deep-link params
    try {
      var params = new URLSearchParams(window.location.search);
      var editId = params.get('edit_event_id');
      var gameParam = params.get('game');
      if (editId) {
        AdminApi.getEvent(editId)
          .then(function(evt) { setEditingEvent(evt); setActivePage('edit-wizard'); })
          .catch(function(err) { showToast('Could not load event: ' + err.message, 'error'); });
        // Clean URL so refresh doesn't re-trigger
        window.history.replaceState({}, '', '/v2/organizer.html');
      } else if (gameParam) {
        // ?game=ID — jump straight to monitor for that game
        setSelectedGameId(gameParam);
        setActivePage('monitor');
        window.history.replaceState({}, '', '/v2/organizer.html');
      }
    } catch (_) {}
  }, [authState]);

  function refreshGames() {
    return Promise.all([
      AdminApi.listGames().catch(function() { return []; }),
      AdminApi.listEvents().catch(function() { return []; })
    ]).then(function(results) {
      var gameList = Array.isArray(results[0]) ? results[0] : (results[0].games || []);
      var eventList = Array.isArray(results[1]) ? results[1] : (results[1].events || []);
      // Find events that don't yet have a game/session — surface as draft rows
      var gameEventIds = {};
      gameList.forEach(function(g) { if (g.event_id) gameEventIds[g.event_id] = true; });
      var draftEvents = eventList.filter(function(e) { return !gameEventIds[e.event_id]; });
      // Normalize draft events into the row shape expected by the dashboard
      var draftRows = draftEvents.map(function(e) {
        var cfg = {};
        try { cfg = typeof e.config === 'string' ? JSON.parse(e.config) : (e.config || {}); } catch(_) { cfg = {}; }
        return {
          game_id: e.event_id,
          event_id: e.event_id,
          join_code: '— draft —',
          name: e.name,
          location: e.location,
          created_at: e.created_at,
          current_phase: 'draft',
          is_event_draft: true,
          event_type: cfg.event_type || e.event_type || ''
        };
      });
      setGames(draftRows.concat(gameList));
    })
    .catch(function(err) { console.error('[organizer] refreshGames failed:', err); });
  }

  function refreshMetrics() {
    AdminApi.metricsOverview()
      .then(function(data) { setMetrics(data); })
      .catch(function(err) { console.error('[organizer] metrics failed:', err); });
  }

  // --- Fetch game detail (component-level so it can be passed as prop) ---
  function fetchDetail() {
    if (!selectedGameId) return;
    Promise.all([
      AdminApi.getGame(selectedGameId),
      AdminApi.getLeaderboard(selectedGameId).catch(function() { return []; }),
      AdminApi.getAllPlayers(selectedGameId).catch(function() { return []; }),
      AdminApi.getGamePhase(selectedGameId).catch(function() { return { phase: 'unknown' }; }),
      AdminApi.getTimerStatus(selectedGameId).catch(function() { return {}; }),
    ]).then(function(results) {
      setGameDetail({
        game: results[0],
        leaderboard: Array.isArray(results[1]) ? results[1] : results[1].leaderboard || [],
        players: Array.isArray(results[2]) ? results[2] : results[2].players || [],
        phase: results[3].phase || results[3],
        timer: results[4],
      });
    }).catch(function(err) {
      console.error('[organizer] game detail fetch failed:', err);
    });
  }

  // --- Auto-poll game detail when a game is selected ---
  React.useEffect(function() {
    if (!selectedGameId) { setGameDetail(null); return; }
    fetchDetail();
    // Poll every 5s when on monitor page
    var interval = setInterval(fetchDetail, 5000);
    return function() { clearInterval(interval); };
  }, [selectedGameId]);

  // --- Create game handler ---
  function handleCreateGame(name, location) {
    var createdBy = admin ? admin.email : '';
    setLoading(true);
    return AdminApi.createGame(name, location, createdBy)
      .then(function(data) {
        showToast('Game created: ' + data.game_id, 'ok');
        refreshGames();
        return data;
      })
      .catch(function(err) {
        showToast('Create failed: ' + err.message, 'error');
        throw err;
      })
      .finally(function() { setLoading(false); });
  }

  // --- Delete game handler ---
  function handleDeleteGame(gameId) {
    var row = games.find(function(g) { return g.game_id === gameId; });
    var isDraft = row && row.is_event_draft;
    var label = isDraft ? 'event ' + row.event_id : 'game ' + gameId;
    if (!confirm('Delete ' + label + '? This cannot be undone.')) return;
    var apiCall = isDraft ? AdminApi.deleteEvent(row.event_id) : AdminApi.deleteGame(gameId);
    apiCall
      .then(function() {
        showToast(isDraft ? 'Event deleted' : 'Game deleted', 'ok');
        if (selectedGameId === gameId) setSelectedGameId(null);
        refreshGames();
      })
      .catch(function(err) { showToast('Delete failed: ' + err.message, 'error'); });
  }

  // --- Phase control handlers ---
  function handleSetPhase(phase) {
    if (!selectedGameId) { showToast('Select a game first', 'error'); return; }
    AdminApi.setGamePhase(selectedGameId, phase)
      .then(function() {
        showToast('Phase → ' + phase, 'ok');
        // Optimistic update so UI reacts immediately (no 5s wait)
        setGameDetail(function(prev) {
          if (!prev) return prev;
          return Object.assign({}, prev, { phase: phase });
        });
      })
      .catch(function(err) { showToast('Phase change failed: ' + err.message, 'error'); });
  }

  function handleTimerAction(action, phaseId, value) {
    if (!selectedGameId) return;
    var gameId = selectedGameId;
    var pid = phaseId || 'quiz';
    var p;
    if (action === 'start') {
      // Ensure game phase and sub_phase are aligned with the timer's phase, then start.
      // Uses local gameDetail.phase to avoid an extra round-trip (idempotent if already correct).
      var currentPhase = gameDetail && gameDetail.phase;
      var phaseFix = (currentPhase !== 'playing')
        ? AdminApi.setGamePhase(gameId, 'playing')
        : Promise.resolve();
      p = phaseFix
        .then(function() { return AdminApi.setSubPhase(gameId, pid); })
        .then(function() { return AdminApi.startTimer(gameId, pid); });
      p.then(function() { showToast('Phase advanced + timer started', 'ok'); })
       .catch(function(err) { showToast('Timer start failed: ' + err.message, 'error'); });
      return;
    } else if (action === 'pause') {
      p = AdminApi.pauseTimer(gameId, pid);
    } else if (action === 'restart') {
      p = AdminApi.restartTimer(gameId);
    } else if (action === 'set-duration') {
      p = AdminApi.setTimerDuration(gameId, pid, value);
    } else if (action === 'extend') {
      p = AdminApi.extendTimer(gameId, pid, value);
    } else return;
    p.then(function() { showToast('Timer ' + action, 'ok'); })
     .catch(function(err) { showToast('Timer failed: ' + err.message, 'error'); });
  }

  function handleResetGame() {
    if (!selectedGameId) return;
    AdminApi.resetGame(selectedGameId)
      .then(function() { showToast('Game reset', 'ok'); })
      .catch(function(err) { showToast('Reset failed: ' + err.message, 'error'); });
  }

  // --- Breadcrumbs ---
  var breadcrumbs = React.useMemo(function() {
    switch (activePage) {
      case 'sessions':      return ['Workspace', 'Sessions'];
      case 'overview':      return ['Workspace', 'Overview'];
      case 'question-bank': return ['Workspace', 'Content library'];
      case 'content-library': return ['Workspace', 'Content library'];
      case 'monitor':       return ['Operate', 'Live monitor', selectedGameId || ''];
      case 'proctor':       return ['Operate', 'Proctor queue'];
      case 'results':       return ['Operate', 'Results & reports'];
      case 'settings':      return ['System', 'Settings'];
      case 'create-wizard': return ['Workspace', 'New session'];
      default:              return ['Workspace', 'Sessions'];
    }
  }, [activePage, selectedGameId]);

  // --- Navigate to monitor for a specific game ---
  function openMonitor(gameId) {
    setSelectedGameId(gameId);
    setActivePage('monitor');
  }

  // --- Render ---

  // Checking auth
  if (authState === 'checking') {
    return (
      <div className="auth-check">
        <div className="spinner"></div>
        <p>Verifying session…</p>
      </div>
    );
  }

  // Login screen
  if (authState === 'login') {
    return (
      <>
        <window.OrgLoginScreen onLogin={handleLogin} loading={loading} />
        {toast && <div className={"toast " + toast.type}>{toast.msg}</div>}
      </>
    );
  }

  // Authenticated — render app shell
  var pageContent;
  switch (activePage) {
    case 'sessions':
      pageContent = (
        <window.OrgSessionsDashboard
          games={games}
          metrics={metrics}
          onCreateGame={handleCreateGame}
          onDeleteGame={handleDeleteGame}
          onOpenMonitor={openMonitor}
          onRefresh={function() { refreshGames(); }}
          onNavigate={setActivePage}
          onEditGame={function(game) {
            if (!game.event_id) return;
            AdminApi.getEvent(game.event_id)
              .then(function(evt) { setEditingEvent(evt); setActivePage('edit-wizard'); })
              .catch(function(err) { showToast('Could not load event: ' + err.message, 'error'); });
          }}
          loading={loading}
        />
      );
      break;

    case 'overview':
      pageContent = (
        <window.OrgOverviewPage metrics={metrics} onRefresh={refreshMetrics} />
      );
      break;

    case 'monitor':
      if (selectedGameId && gameDetail && selectedEventType === 'tech-day' && window.OrgMonitorTechDay) {
        pageContent = (
          <window.OrgMonitorTechDay
            gameId={selectedGameId}
            detail={gameDetail}
            onSelectGame={setSelectedGameId}
            showToast={showToast}
            onRefresh={fetchDetail}
          />
        );
      } else {
        pageContent = (
          <window.OrgMonitorPage
            gameId={selectedGameId}
            detail={gameDetail}
            games={games}
            onSelectGame={setSelectedGameId}
            onSetPhase={handleSetPhase}
            onTimerAction={handleTimerAction}
            onResetGame={handleResetGame}
            onForceRefresh={fetchDetail}
            showToast={showToast}
          />
        );
      }
      break;

    case 'question-bank':
    case 'content-library':
      pageContent = (
        <window.OrgContentLibraryPage
          games={games}
          showToast={showToast}
          onNavigate={function(page) { setActivePage(page); }}
        />
      );
      break;

    case 'results':
      pageContent = (
        <window.OrgResultsPage games={games} showToast={showToast} />
      );
      break;

    case 'settings':
      pageContent = (
        <window.OrgSettingsPage admin={admin} showToast={showToast} />
      );
      break;

    case 'proctor':
      pageContent = (
        <window.OrgProctorPage games={games} showToast={showToast} />
      );
      break;

    case 'create-wizard':
      pageContent = (
        <window.OrgCreateWizard
          admin={admin}
          showToast={showToast}
          onNavigate={setActivePage}
          onSaveDraftAndNavigate={function(eventData) {
            setEditingEvent(eventData);
            refreshGames();
            setActivePage('content-library');
          }}
          onComplete={function(eventData, meta) {
            showToast('Session created successfully!', 'ok');
            refreshGames().then(function() {
              if (meta && meta.eventType === 'tech-day') {
                var eid = eventData && (eventData.event_id || eventData.id) || '';
                window.location.href = '/v2/tech-day-speakers?event_id=' + eid;
              } else {
                setActivePage('sessions');
              }
            });
          }}
          onCancel={function() {
            setActivePage('sessions');
          }}
        />
      );
      break;

    case 'edit-wizard':
      pageContent = (
        <window.OrgCreateWizard
          admin={admin}
          editEvent={editingEvent}
          showToast={showToast}
          onNavigate={setActivePage}
          onComplete={function(eventData, meta) {
            showToast('Event updated successfully!', 'ok');
            refreshGames().then(function() {
              setEditingEvent(null);
              if (meta && meta.eventType === 'tech-day') {
                var eid = editingEvent ? editingEvent.event_id : (eventData && (eventData.event_id || eventData.id) || '');
                window.location.href = '/v2/tech-day-speakers?event_id=' + eid;
              } else {
                setActivePage('sessions');
              }
            });
          }}
          onCancel={function() {
            setEditingEvent(null);
            setActivePage('sessions');
          }}
        />
      );
      break;

    default:
      pageContent = (
        <window.OrgPlaceholderPage pageId={activePage} />
      );
  }
  return (
    <div className="app">
      <window.OrgSidebar
        activePage={activePage}
        onNavigate={setActivePage}
        admin={admin}
        onLogout={handleLogout}
        gameCount={games.length}
      />
      <main className="main">
        <window.OrgTopbar
          breadcrumbs={breadcrumbs}
          onCreateGame={handleCreateGame}
          onNavigate={setActivePage}
          admin={admin}
        />
        <div className="page">
          {pageContent}
        </div>
        <window.OrgDocFooter />
      </main>
      {toast && <div className={"toast " + toast.type}>{toast.msg}</div>}
    </div>
  );
};

// ---------------------------------------------------------------------------
// TweakPanel — Ctrl+Shift+T toggled panel for CSS custom property overrides
// ---------------------------------------------------------------------------
(function () {
  var HUES = [
    { label: 'Cisco', value: 230 },
    { label: 'F1',    value: 12  },
    { label: 'Match', value: 152 },
    { label: 'TV',    value: 300 },
  ];

  window.OrgTweakPanel = function OrgTweakPanel() {
    var ref = React.useState(false), visible = ref[0], setVisible = ref[1];
    var ref2 = React.useState(230), activeHue = ref2[0], setActiveHue = ref2[1];

    React.useEffect(function() {
      function onKey(e) {
        if (e.ctrlKey && e.shiftKey && e.key === 'T') setVisible(function(v) { return !v; });
      }
      window.addEventListener('keydown', onKey);
      return function() { window.removeEventListener('keydown', onKey); };
    }, []);

    function applyHue(hue) {
      setActiveHue(hue);
      var root = document.documentElement;
      root.style.setProperty('--brand', 'oklch(62% 0.18 ' + hue + ')');
      root.style.setProperty('--brand-soft', 'oklch(28% 0.08 ' + hue + ')');
    }

    if (!visible) return null;
    return (
      <div className="tweak" style={{display:'block'}}>
        <h5>Brand hue</h5>
        <div className="row">
          {HUES.map(function(h) {
            return <button key={h.label} className={activeHue === h.value ? 'active' : ''} onClick={function() { applyHue(h.value); }}>{h.label}</button>;
          })}
        </div>
      </div>
    );
  };
})();

// ---------------------------------------------------------------------------
// Mount
// ---------------------------------------------------------------------------
(function () {
  var container = document.getElementById('app');
  if (!container) {
    console.error('[organizer-app] No #app element found.');
    return;
  }
  var root = ReactDOM.createRoot(container);
  root.render(
    <>
      <window.OrganizerApp />
      <window.OrgTweakPanel />
    </>
  );
})();
