// Main App — no sidebar, tweaks panel
function App() {
  const techniques = [...(window.TECHNIQUES_A || []), ...(window.TECHNIQUES_B || [])];

  const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
    "accentColor": "#3b82f6",
    "cardColumns": "auto",
    "compactCards": false,
    "showTagline": true,
    "showFamilyBadge": true,
    "listPaneWidth": 380
  }/*EDITMODE-END*/;

  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const proposal = useProposal();
  const isMobile = useIsMobile();
  const [theme, toggleTheme] = useTheme();

  // State
  const [search, setSearch] = React.useState('');
  const [activeId, setActiveId] = React.useState(null);
  const [filters, setFilters] = React.useState({ family:'', budget:'', stage:'' });
  const [showRecommender, setShowRecommender] = React.useState(false);
  const [showBuilder, setShowBuilder] = React.useState(false);
  const [filtersOpen, setFiltersOpen] = React.useState(false);

  // Deep-link
  React.useEffect(() => {
    const hash = window.location.hash.replace('#','');
    if (hash) setActiveId(hash);
    // Empty hash means the user navigated back — close the detail view.
    // Matters most on mobile, where detail is full-screen and back is the natural exit.
    const onHash = () => { setActiveId(window.location.hash.replace('#','') || null); };
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);
  React.useEffect(() => {
    if (activeId) window.location.hash = activeId;
    else window.history.replaceState(null,'',window.location.pathname);
  }, [activeId]);

  const score = (t, q) => {
    if (!q) return 1;
    const lq = q.toLowerCase();
    let s = 0;
    if (t.name.toLowerCase().includes(lq)) s += 10;
    if (t.shortName?.toLowerCase().includes(lq)) s += 8;
    if ((t.tags.synonyms||[]).some(syn => syn.toLowerCase().includes(lq))) s += 7;
    if ((t.tags.businessProblems||[]).some(b => b.toLowerCase().includes(lq))) s += 5;
    if ((t.tags.objectives||[]).some(o => o.toLowerCase().includes(lq))) s += 5;
    if ((t.tags.useCases||[]).some(u => u.toLowerCase().includes(lq))) s += 4;
    if ((t.tags.questionTypes||[]).some(qt => qt.toLowerCase().includes(lq))) s += 3;
    if ((t.tags.outputTypes||[]).some(ot => ot.toLowerCase().includes(lq))) s += 3;
    if (t.tagline?.toLowerCase().includes(lq)) s += 3;
    if (t.family?.toLowerCase().includes(lq)) s += 2;
    return s;
  };

  const filtered = techniques
    .filter(t => {
      if (filters.family && t.family !== filters.family) return false;
      if (filters.budget && t.tags.budgetLevel !== filters.budget) return false;
      if (filters.stage && !(t.tags.studyStages||[]).includes(filters.stage)) return false;
      if (search) return score(t, search) > 0;
      return true;
    })
    .sort((a,b) => search ? score(b,search) - score(a,search) : 0);

  const activeTech = techniques.find(t => t.id === activeId);
  const families = [...new Set(techniques.map(t => t.family))];
  const stages = [...new Set(techniques.flatMap(t => t.tags.studyStages||[]))];
  const hasFilters = filters.family || filters.budget || filters.stage;
  const clearAll = () => { setSearch(''); setFilters({ family:'', budget:'', stage:'' }); };

  const accent = tweaks.accentColor || COLORS.indigo[700];

  // Card grid columns
  const gridCols = tweaks.compactCards
    ? 'repeat(auto-fill, minmax(200px, 1fr))'
    : tweaks.cardColumns === 'auto'
    ? 'repeat(auto-fill, minmax(280px, 1fr))'
    : tweaks.cardColumns === '2' ? 'repeat(2, 1fr)'
    : tweaks.cardColumns === '3' ? 'repeat(3, 1fr)'
    : 'repeat(auto-fill, minmax(280px, 1fr))';

  return (
    <div style={{ display:'flex', height:'100vh', flexDirection:'column',
      fontFamily:"'Inter', system-ui, sans-serif", background:COLORS.slate[50],
      overflow:'hidden', fontSize:14 }}>

      {/* SITE NAV — mirrors the shell in index.php so this page reads as part of
          DataIngrid. Desktop only: on mobile the ~52px would eat scarce height. */}
      {!isMobile && <SiteNav />}

      {/* TOP BAR — single row on desktop; on mobile it wraps to two rows
          (brand + actions, then a full-width search) so nothing gets squeezed out. */}
      <div style={{ height: isMobile ? 'auto' : 58, background:COLORS.slate[100],
        borderBottom:`1px solid ${COLORS.slate[200]}`,
        display:'flex', alignItems:'center',
        flexWrap: isMobile ? 'wrap' : 'nowrap',
        padding: isMobile ? '8px 12px' : '0 24px',
        paddingTop: isMobile ? 'calc(8px + env(safe-area-inset-top))' : 0,
        gap: isMobile ? 8 : 14, flexShrink:0,
        boxShadow:'0 1px 3px rgba(0,0,0,0.04)' }}>

        {/* Brand */}
        <div style={{ display:'flex', alignItems:'center', gap:10,
          marginRight: isMobile ? 'auto' : 4, minWidth:0 }}>
          <div style={{ width:34, height:34, borderRadius:10,
            background:'linear-gradient(135deg, #3b82f6, #8b5cf6)',
            display:'flex', alignItems:'center', justifyContent:'center', fontSize:17, color:'white' }}>⚗</div>
          <div style={{ lineHeight:1.2 }}>
            <div style={{ fontWeight:800, fontSize:13.5, color:COLORS.slate[900], letterSpacing:'-0.01em' }}>Technique Library</div>
            <div style={{ fontSize:10, color:COLORS.slate[400], fontWeight:500 }}>Healthcare &amp; Pharma Research</div>
          </div>
        </div>

        {!isMobile && <div style={{ width:1, height:28, background:COLORS.slate[200] }} />}

        {/* Search — own full-width row on mobile (order:1 puts it after the buttons) */}
        <div style={{ flex: isMobile ? '1 1 100%' : 1, maxWidth: isMobile ? 'none' : 520,
          position:'relative', order: isMobile ? 1 : 0 }}>
          <span style={{ position:'absolute', left:12, top:'50%', transform:'translateY(-50%)',
            color:COLORS.slate[400], fontSize:15, pointerEvents:'none' }}>⌕</span>
          <input type="text"
            placeholder={isMobile ? 'Search techniques…' : 'Search by technique, problem, objective, use case, synonym…'}
            value={search} onChange={e => setSearch(e.target.value)}
            style={{ width:'100%', padding:'8px 34px 8px 36px', borderRadius:10,
              border:`1.5px solid ${search ? accent : COLORS.slate[200]}`,
              /* 16px on mobile — anything smaller makes iOS Safari zoom on focus */
              fontSize: isMobile ? 16 : 13,
              background: search ? accent+'08' : COLORS.slate[50],
              color:COLORS.slate[800], boxSizing:'border-box', transition:'all 0.15s', outline:'none' }}
          />
          {search && (
            <button onClick={() => setSearch('')}
              style={{ position:'absolute', right:8, top:'50%', transform:'translateY(-50%)',
                border:'none', background:'none', cursor:'pointer', color:COLORS.slate[400], fontSize:18, lineHeight:1 }}>×</button>
          )}
        </div>

        {/* Filters */}
        <button onClick={() => setFiltersOpen(o => !o)}
          aria-label="Filters" title="Filters"
          style={{ padding: isMobile ? '7px 11px' : '7px 14px', borderRadius:10,
            border:`1.5px solid ${hasFilters ? accent : COLORS.slate[200]}`,
            background: hasFilters ? accent+'22' : COLORS.slate[100], cursor:'pointer',
            fontSize:12, fontWeight:600, color: hasFilters ? accent : COLORS.slate[600],
            display:'flex', alignItems:'center', gap:6, transition:'all 0.12s', flexShrink:0 }}>
          ⚙{isMobile ? '' : ' Filters'} {hasFilters && <span style={{ background:accent, color:'white', borderRadius:999,
            width:18, height:18, display:'inline-flex', alignItems:'center', justifyContent:'center',
            fontSize:10, fontWeight:800 }}>{Object.values(filters).filter(Boolean).length}</span>}
        </button>

        {/* Proposal builder */}
        <button onClick={() => setShowBuilder(true)}
          aria-label="Proposal builder" title="Proposal builder"
          style={{ padding: isMobile ? '7px 11px' : '7px 14px', borderRadius:10,
            border:`1.5px solid ${proposal.cart.length ? accent : COLORS.slate[200]}`,
            background: proposal.cart.length ? accent+'22' : COLORS.slate[100], cursor:'pointer',
            fontSize:12, fontWeight:600, color: proposal.cart.length ? accent : COLORS.slate[600],
            display:'flex', alignItems:'center', gap:6, transition:'all 0.12s', flexShrink:0 }}>
          ▤{isMobile ? '' : ' Proposal'} {proposal.cart.length > 0 && <span style={{ background:accent, color:'white', borderRadius:999,
            width:18, height:18, display:'inline-flex', alignItems:'center', justifyContent:'center',
            fontSize:10, fontWeight:800 }}>{proposal.cart.length}</span>}
        </button>

        {/* Theme toggle */}
        <ThemeToggle theme={theme} onToggle={toggleTheme} compact={isMobile} />

        {/* Recommender */}
        <button onClick={() => setShowRecommender(true)}
          aria-label="Find a Method"
          style={{ padding: isMobile ? '8px 12px' : '8px 16px', borderRadius:10, border:'none',
            background:'linear-gradient(135deg, #3b82f6, #2563eb)', cursor:'pointer',
            fontSize:12.5, fontWeight:700,
            color:'white', whiteSpace:'nowrap', flexShrink:0,
            boxShadow:'0 4px 18px rgba(59,130,246,.35)' }}>
          ✦ {isMobile ? 'Find' : 'Find a Method'}
        </button>
      </div>

      {/* FILTER BAR */}
      {filtersOpen && (
        <div style={{ background:COLORS.slate[100], borderBottom:`1px solid ${COLORS.slate[200]}`,
          padding: isMobile ? '10px 12px' : '10px 24px',
          display:'flex', gap:10, alignItems:'center', flexWrap:'wrap',
          boxShadow:'0 2px 4px rgba(0,0,0,0.03)' }}>
          <span style={{ fontSize:11, fontWeight:700, color:COLORS.slate[400], letterSpacing:'0.06em' }}>FILTER:</span>
          {[
            { key:'family', label:'Family', options:[{v:'',l:'All families'},...families.map(f=>({v:f,l:f}))] },
            { key:'budget', label:'Budget', options:[{v:'',l:'All budgets'},{v:'low',l:'Low'},{v:'low-medium',l:'Low–Medium'},{v:'medium',l:'Medium'},{v:'medium-high',l:'Medium–High'},{v:'high',l:'High'}] },
            { key:'stage', label:'Stage', options:[{v:'',l:'All stages'},...stages.map(s=>({v:s,l:s}))] },
          ].map(({ key, options }) => (
            <select key={key} value={filters[key]} onChange={e => setFilters(f => ({...f, [key]:e.target.value}))}
              style={{ padding:'6px 10px', borderRadius:8, border:`1px solid ${filters[key] ? accent : COLORS.slate[200]}`,
                fontSize:12, background: filters[key] ? accent+'08' : 'white', color:COLORS.slate[700],
                cursor:'pointer', fontWeight: filters[key] ? 600 : 400 }}>
              {options.map(o => <option key={o.v} value={o.v}>{o.l}</option>)}
            </select>
          ))}
          {hasFilters && (
            <button onClick={() => setFilters({ family:'', budget:'', stage:'' })}
              style={{ padding:'5px 10px', border:`1px solid ${COLORS.rose[200]}`, borderRadius:8,
                background:COLORS.slate[100], color:COLORS.rose[600], fontSize:12, cursor:'pointer', fontWeight:600 }}>
              × Clear
            </button>
          )}
        </div>
      )}

      {/* BODY */}
      <div style={{ flex:1, overflow:'hidden', display:'flex', minHeight:0 }}>

        {/* CARD LIST PANE — hidden on mobile while a technique is open, so the
            detail panel gets the full width instead of a ~10px sliver. */}
        {!(isMobile && activeTech) && (
        <div style={{
          flex: (activeTech && !isMobile) ? `0 0 ${tweaks.listPaneWidth}px` : '1 1 auto',
          borderRight: (activeTech && !isMobile) ? `1px solid ${COLORS.slate[200]}` : 'none',
          overflowY:'auto', WebkitOverflowScrolling:'touch',
          padding: isMobile ? '16px 12px' : '20px 24px',
          background:COLORS.slate[50], minWidth:0
        }}>
          {/* Header */}
          <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:16 }}>
            <span style={{ fontSize:13, fontWeight:700, color:COLORS.slate[600] }}>
              {search || hasFilters
                ? <>{filtered.length} result{filtered.length!==1?'s':''} <button onClick={clearAll}
                    style={{ fontSize:11, color:accent, background:'none', border:'none', cursor:'pointer', fontWeight:700, marginLeft:6 }}>Clear all ×</button></>
                : `${techniques.length} techniques`}
            </span>
            {!activeTech && (
              <button onClick={() => setShowRecommender(true)}
                style={{ fontSize:11.5, color:accent, background:accent+'10',
                  border:`1px solid ${accent}30`, borderRadius:8, padding:'4px 10px', cursor:'pointer', fontWeight:600 }}>
                ✦ Not sure? Get a recommendation
              </button>
            )}
          </div>

          {filtered.length === 0 && (
            <EmptyState title="No techniques match" subtitle='Try "pricing", "segmentation", "trade-off", or "ranking"'
              action={<button onClick={() => setShowRecommender(true)}
                style={{ marginTop:16, padding:'9px 20px', borderRadius:10, border:'none',
                  background:accent, color:'white', fontSize:13, fontWeight:700, cursor:'pointer' }}>
                ✦ Use Guided Recommender
              </button>} />
          )}

          {filtered.length > 0 && (
            <div style={{ display:'grid',
              gridTemplateColumns: (activeTech || isMobile) ? '1fr' : gridCols,
              gap: tweaks.compactCards ? 8 : 12 }}>
              {filtered.map(t => (
                <TechniqueCard key={t.id} technique={t}
                  onClick={id => setActiveId(activeId === id ? null : id)}
                  isActive={activeId === t.id}
                  compact={(!!activeTech && !isMobile) || tweaks.compactCards}
                  accentOverride={accent}
                  showTagline={tweaks.showTagline}
                  showFamilyBadge={tweaks.showFamilyBadge}
                />
              ))}
            </div>
          )}
        </div>
        )}

        {/* DETAIL PANEL — full width on mobile, where it replaces the list */}
        {activeTech && (
          <div style={{ flex:'1 1 auto', overflowY:'auto', WebkitOverflowScrolling:'touch',
            background:COLORS.slate[100], minWidth:0, width: isMobile ? '100%' : 'auto' }}>
            <TechniqueDetail technique={activeTech} onClose={() => setActiveId(null)}
              isMobile={isMobile}
              inCart={proposal.inCart(activeTech.id)}
              onToggleCart={proposal.toggleCart}
              ctx={proposal.ctx} />
          </div>
        )}
      </div>

      {/* RECOMMENDER MODAL */}
      <Modal open={showRecommender} onClose={() => setShowRecommender(false)} title="Guided Method Recommender" width={560}>
        <Recommender techniques={techniques}
          onSelect={id => { setActiveId(id); setShowRecommender(false); }}
          onClose={() => setShowRecommender(false)} />
      </Modal>

      {/* PROPOSAL BUILDER MODAL */}
      <Modal open={showBuilder} onClose={() => setShowBuilder(false)} title="Proposal Builder" width={1000}>
        <ProposalBuilder allTechniques={techniques} proposal={proposal}
          onOpenTechnique={id => { setActiveId(id); setShowBuilder(false); }} />
      </Modal>

      {/* TWEAKS PANEL */}
      <TweaksPanel>
        <TweakSection label="Accent Colour">
          <TweakColor tweakKey="accentColor" label="Primary accent" />
        </TweakSection>
        <TweakSection label="Card Grid">
          <TweakRadio tweakKey="cardColumns" label="Columns" options={[
            { label:'Auto', value:'auto' },
            { label:'2', value:'2' },
            { label:'3', value:'3' },
          ]} />
          <TweakToggle tweakKey="compactCards" label="Compact cards" />
        </TweakSection>
        <TweakSection label="Card Content">
          <TweakToggle tweakKey="showTagline" label="Show tagline" />
          <TweakToggle tweakKey="showFamilyBadge" label="Show family badge" />
        </TweakSection>
        <TweakSection label="Detail Panel">
          <TweakSlider tweakKey="listPaneWidth" label="List pane width" min={280} max={520} step={20} />
        </TweakSection>
      </TweaksPanel>
    </div>
  );
}

// Mount
const appRoot = ReactDOM.createRoot(document.getElementById('root'));
appRoot.render(<App />);
