// app.jsx - main shell, view router, filter pipeline

const { useState, useMemo, useEffect } = React;

// Microsoft Forms feedback survey - linked from the bar under every page.
const FEEDBACK_URL = 'https://forms.cloud.microsoft/Pages/ResponsePage.aspx?id=Kh3WCJKMCEi47oT2rrORzsQUrBTAcQVFoWuIaSF_saNUQ1pCMkxHU0FGVldSM1ZKRUlHUEo4SE1QOC4u';

function LoginScreen({ onAuth }) {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');

  function handleSubmit(e) {
    e.preventDefault();
    if (username === 'gea' && password === 'system_map') {
      sessionStorage.setItem('gea_authed', '1');
      onAuth();
    } else {
      setError('Invalid username or password.');
      setPassword('');
    }
  }

  return (
    <div className="login-overlay">
      <div className="login-card">
        <div className="login-brand">
          <img
            src="assets/gea-logo-mark-reversed.svg"
            alt="Global Energy Alliance"
            style={{ display: 'block', height: 46, width: 'auto', flexShrink: 0 }}
          />
          <div>
            <div className="login-brand-title">Global Initiatives <em>Atlas</em></div>
            <div className="login-brand-sub">Powered by the Global Energy Alliance and Systemiq</div>
          </div>
        </div>
        <form className="login-form" onSubmit={handleSubmit}>
          <label className="login-label">
            Username
            <input
              className="login-input"
              type="text"
              autoComplete="username"
              value={username}
              onChange={e => { setUsername(e.target.value); setError(''); }}
              autoFocus
            />
          </label>
          <label className="login-label">
            Password
            <input
              className="login-input"
              type="password"
              autoComplete="current-password"
              value={password}
              onChange={e => { setPassword(e.target.value); setError(''); }}
            />
          </label>
          {error && <div className="login-error">{error}</div>}
          <button className="login-btn" type="submit">Sign in</button>
        </form>
      </div>
    </div>
  );
}

// Tabs hidden from the UI (keep entries below if you want to re-enable):
//   { id: 'directory',    num: '04', name: 'Directory',                                            subtitle: 'All organisations as cards. Sort, search, drill in.' },
//   { id: 'india-demand', num: '05', name: 'Regional System Map · India - Demand & Supply',        subtitle: 'Two hex-map panels side-by-side: where demand is growing and reliability is failing (Panel A) vs where RE generation and the BESS pipeline sit (Panel B). The gap is the investable opportunity.' },
const VIEWS = [
  { id: 'value-chain',       num: '01', name: 'Energy Ecosystem Infographic',                        subtitle: "Schematic of the energy ecosystem, with from top to bottom highlighted the \"influencers\", the different barriers these \"influencers\" address and the energy ecosystem they are impacting. Each node is colour-coded by Global Energy Alliance's pillars  (Energy access = yellow, Grid modernization = green dashed). Click a node for a description, or use the legend cards to highlight pillar-specific segments." },
  { id: 'matrix',            num: '02', name: 'Global Initiatives Heat Map',                          subtitle: 'A table view: which organizations work on each value-chain segment, by region — or by barrier (toggle the y-axis at the top). Sovereign governments, universities, global consultancies and contractors and utilities and operators excluded from this overview. Spot where coverage is thin and where overlap may exist at the press of a button and use the search bar to find relevant organizations. ' },
  { id: 'network',           num: '03', name: 'Global Collaboration Network',         subtitle: 'Who works with whom. Reveals well-networked actors, isolated initiatives, and partnership gaps across the system. Use the search bar to find relevant organizations. Hover a node to highlight its partners. Click for full details. Edges are symmetric — each pair appears once. Nodes represent officially published MoU\'s, partnerships or joint programmes.' },
  { id: 'india-value-chain', num: '04', name: 'India · Energy Ecosystem Infographic',                subtitle: 'India-focused view of the energy ecosystem — same schematic structure as the global maps, scoped to the India context. Click value chain segments to reveal information about that value chain segment in India.' },
  { id: 'india-players',     num: '05', name: 'India · Industry players and initiatives',  subtitle: 'Same energy ecosystem columns as the global maps. Top band: industry players. Bottom band: initiatives & programmes. Anchor organizations shown in bold.' },
  { id: 'india-network',     num: '06', name: 'India · Regional Collaboration Network',                subtitle: 'Collaboration network of the global initiatives whose mandate covers India. Hover a node to highlight its partners. Click for full details. Edges are symmetric — each pair appears once. Nodes represent officially published MoU\'s, partnerships or joint programmes.' },
  { id: 'methodology',       num: '07', name: 'Methodology',                                            subtitle: 'How organizations are categorised across this atlas, what the data does and does not cover, and the biases to keep in mind when reading every view. The ? bubbles throughout the tool link here.' },
];

// Returns a relevance score (0 = no match). Higher = more relevant.
function searchScore(org, q) {
  if (!q) return 0;
  const needle = q.toLowerCase().trim();
  if (!needle) return 0;

  const name = (org.name || '').toLowerCase();
  const desc = (org.description || '').toLowerCase();
  const detail = (org.detail || '').toLowerCase();
  const topics = (org.topics || []).map(s => String(s).toLowerCase());
  const regions = (org.regions || []).map(s => String(s).toLowerCase());
  const collabs = (org.collaborators || []).map(s => String(s).toLowerCase());

  let score = 0;

  // Name signals - by far the strongest
  if (name === needle) score += 1000;
  else if (name.startsWith(needle)) score += 600;
  else {
    // Word-boundary match in name
    const re = new RegExp('\\b' + needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
    if (re.test(org.name || '')) score += 400;
    else if (name.includes(needle)) score += 200;
  }
  // Shorter names rank higher among name matches (more "exact-feeling")
  if (score > 0) score += Math.max(0, 40 - name.length);

  // Topic / region exact or contains
  if (topics.some(t => t === needle)) score += 120;
  else if (topics.some(t => t.includes(needle))) score += 50;
  if (regions.some(r => r === needle)) score += 100;
  else if (regions.some(r => r.includes(needle))) score += 40;

  // Known collaborators
  if (collabs.some(c => c.includes(needle))) score += 30;

  // Description / detail - weakest. Word-boundary stronger than substring.
  const wordRe = new RegExp('\\b' + needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
  if (wordRe.test(org.description || '')) score += 25;
  else if (desc.includes(needle)) score += 8;
  if (wordRe.test(org.detail || '')) score += 12;
  else if (detail.includes(needle)) score += 4;

  return score;
}

function searchMatches(org, q) { return searchScore(org, q) > 0; }

function passes(org, filters) {
  const checkArr = (filterKey, orgKey) => {
    const f = filters[filterKey];
    if (!f || !f.length) return true;
    return f.some((v) => org[orgKey].includes(v));
  };
  if (!checkArr('regions', 'regions')) return false;
  if (!checkArr('barriers', 'barriers')) return false;
  if (filters.types?.length && !filters.types.includes(org.type)) return false;
  if (filters.pillar?.length) {
    // 'both' orgs satisfy either 'grids' or 'powering' selection.
    // Selecting 'both' explicitly matches only orgs flagged as 'both'.
    const sel = filters.pillar;
    const op = org.pillar;
    const ok =
      sel.includes(op) ||
      (op === 'both' && (sel.includes('grids') || sel.includes('powering')));
    if (!ok) return false;
  }
  return true;
}

function App({ defaultView = 'matrix', autostartTour = false, onHome }) {
  const [activeView, setActiveView] = useState(defaultView);
  // India Network draws on the India dataset's own collaboration edges (from the
  // "Collaboration India" sheet, baked into INDIA_DATA.edges). We show only the
  // organisations that actually participate in a partnership (degree ≥ 1) so the
  // graph is the India collaboration network, not a cloud of isolated nodes.
  const dataset = useMemo(() => {
    if (activeView === 'india-players' || activeView === 'india-demand') return window.INDIA_DATA;
    if (activeView === 'india-network') {
      const base = window.INDIA_DATA;
      const edges = base.edges || [];
      const connected = new Set();
      for (const e of edges) { connected.add(e.a); connected.add(e.b); }
      const initiatives = base.initiatives.filter(o => connected.has(o.id));
      return { ...base, initiatives, edges };
    }
    return window.INITIATIVES_DATA;
  }, [activeView]);
  const { initiatives, edges, facets } = dataset;
  const [selectedOrg, setSelectedOrg] = useState(null);
  const [filters, setFilters] = useState({
    search: '', regions: [], topics: [], stages: [], barriers: [], types: [], funding: [], pillar: [],
  });
  const [highlightOrgId, setHighlightOrgId] = useState(null);
  const [tourActive, setTourActive] = useState(autostartTour);
  // Methodology deep-linking - the ? bubbles across the tool call this to jump
  // to a specific methodology section. The bumped nonce forces a re-scroll even
  // when the same section is requested twice in a row.
  const [methodologyTarget, setMethodologyTarget] = useState(null); // { section, nonce }
  const openMethodology = (section) => {
    setMethodologyTarget(prev => ({ section: section || null, nonce: (prev?.nonce || 0) + 1 }));
    setActiveView('methodology');
  };

  // Clear highlight when search cleared or view changes
  useEffect(() => { setHighlightOrgId(null); }, [activeView]);
  useEffect(() => { if (!filters.search) setHighlightOrgId(null); }, [filters.search]);
  // Toggle body class so layout can make room for the panel
  useEffect(() => {
    const showPanel = !!filters.search && activeView !== 'directory';
    document.body.classList.toggle('has-search-panel', showPanel);
    return () => document.body.classList.remove('has-search-panel');
  }, [filters.search, activeView]);

  const filtered = useMemo(() => {
    let base = initiatives.filter((o) => passes(o, filters));
    // In Directory view, search filters the cards directly (no side panel)
    // and orders them by relevance, overriding the directory's sort buttons
    if (activeView === 'directory' && filters.search) {
      const scored = base
        .map(o => ({ o, s: searchScore(o, filters.search) }))
        .filter(x => x.s > 0)
        .sort((a, b) => b.s - a.s || a.o.name.localeCompare(b.o.name));
      base = scored.map(x => x.o);
    }
    return base;
  }, [initiatives, filters, activeView]);

  const searchResults = useMemo(() => {
    const q = (filters.search || '').trim();
    if (!q) return [];
    const scored = initiatives
      .map(o => ({ o, s: searchScore(o, q) }))
      .filter(x => x.s > 0)
      .sort((a, b) => b.s - a.s || a.o.name.localeCompare(b.o.name));
    return scored.slice(0, 80).map(x => x.o);
  }, [initiatives, filters.search]);

  const view = VIEWS.find((v) => v.id === activeView);

  const ViewComp = {
    matrix: window.MatrixView,
    network: window.NetworkView,
    directory: window.DirectoryView,
    'value-chain': window.ValueChainView,
    'india-value-chain': window.ValueChainIndiaView,
    'india-network': window.IndiaNetworkView,
    'india-demand': window.RegionalIndiaView,
    'india-players': window.IndiaPlayersView,
    methodology: window.MethodologyView,
  }[activeView];

  return (
    <div className="app">
      <header className="app-header">
        <button className="brand brand--btn" onClick={onHome} title="Back to home">
          <div>
            <div className="brand-title">Global Initiatives <em>Atlas</em></div>
            <div className="brand-sub">Powered by the <span className="brand-sub-gea">Global Energy Alliance</span> and Systemiq</div>
          </div>
        </button>
        <button
          className="tour-launch"
          onClick={() => setTourActive(true)}
          title="Take a guided tour of the Atlas"
        >
          <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
            <circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" strokeWidth="2" />
            <path d="M9 9 a3 3 0 1 1 4.2 2.7 c-0.9 0.5 -1.2 1 -1.2 2" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
            <circle cx="12" cy="17.5" r="1.2" fill="currentColor" />
          </svg>
          Take a tour
        </button>
        <a
          className="header-gea-logo"
          href="https://energyalliance.org/"
          target="_blank"
          rel="noopener noreferrer"
          title="Visit the Global Energy Alliance"
        >
          <img src="assets/gea-logo-horizontal-reversed.svg" alt="Global Energy Alliance" />
        </a>
      </header>

      <nav className="tabs" data-tour="tabs">
        {VIEWS.map((v) => (
          <React.Fragment key={v.id}>
            {(v.id === 'india-value-chain' || v.id === 'methodology') && <div className="tabs-separator" />}
            <button
              className={'tab' + (activeView === v.id ? ' is-active' : '')}
              data-tour={'tab-' + v.id}
              onClick={() => setActiveView(v.id)}
            >
              <span>{v.name}</span>
            </button>
          </React.Fragment>
        ))}
      </nav>

      <div className="workspace workspace--no-rail">
        <main className="view" key={activeView}>
          <div className="view-inner">
            <div className="view-title">
              <div>
                <h2>{view.name}</h2>
                <p>{view.subtitle}</p>
              </div>
              {activeView !== 'value-chain' && activeView !== 'india-value-chain' && (
                <div className="view-search" data-tour="search">
                  <input
                    type="text"
                    className="view-search-input"
                    placeholder="Search organizations..."
                    value={filters.search}
                    onChange={(e) => setFilters({ ...filters, search: e.target.value })}
                  />
                  {filters.search && (
                    <button
                      type="button"
                      className="view-search-clear"
                      onClick={() => setFilters({ ...filters, search: '' })}
                      aria-label="Clear search"
                    >×</button>
                  )}
                </div>
              )}
            </div>
            {activeView === 'india-demand' ? (
              <ViewComp />
            ) : activeView === 'methodology' ? (
              <ViewComp methodologyTarget={methodologyTarget} onOpenMethodology={openMethodology} setActiveView={setActiveView} />
            ) : filtered.length === 0 ? (
              <div className="empty">
                <h4>No initiatives match</h4>
              </div>
            ) : ViewComp ? (
              <ViewComp orgs={filtered} allOrgs={initiatives} edges={edges} onPickOrg={setSelectedOrg} filters={filters} setFilters={setFilters} dataset={dataset} highlightOrgId={highlightOrgId} setActiveView={setActiveView} onOpenMethodology={openMethodology} />
            ) : null}

            <div className="page-feedback" data-tour="feedback">
              <span className="page-feedback-text">Spotted something off, or have a suggestion?</span>
              <a
                className="page-feedback-btn"
                href={FEEDBACK_URL}
                target="_blank"
                rel="noopener noreferrer"
              >
                Share feedback
              </a>
            </div>
          </div>
        </main>
      </div>

      {filters.search && activeView !== 'directory' && (
        <SearchPanel
          query={filters.search}
          results={searchResults}
          highlightOrgId={highlightOrgId}
          onPick={(o) => setHighlightOrgId(o.id)}
          onOpen={(o) => setSelectedOrg(o)}
          onClose={() => { setFilters({ ...filters, search: '' }); setHighlightOrgId(null); }}
          facets={facets}
        />
      )}

      <Drawer
        org={selectedOrg}
        allOrgs={initiatives}
        regional={activeView.startsWith('india')}
        onClose={() => setSelectedOrg(null)}
        onPickOrg={setSelectedOrg}
      />

      {tourActive && (
        <TutorialOverlay
          activeView={activeView}
          setActiveView={setActiveView}
          onClose={() => setTourActive(false)}
        />
      )}
    </div>
  );
}

function Root() {
  const [authed, setAuthed] = useState(() => sessionStorage.getItem('gea_authed') === '1');
  const [activeView, setActiveView] = useState(null); // null = landing page
  const [autostartTour, setAutostartTour] = useState(false);

  if (!authed) return <LoginScreen onAuth={() => setAuthed(true)} />;
  if (!activeView) return (
    <LandingPage
      onNavigate={setActiveView}
      onStartTour={() => { setAutostartTour(true); setActiveView('value-chain'); }}
    />
  );
  return (
    <App
      defaultView={activeView}
      autostartTour={autostartTour}
      onHome={() => { setAutostartTour(false); setActiveView(null); }}
    />
  );
}

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