// ============================================================
// App shell — header, controls, grid/table, modal
// ============================================================

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

const ACCENT_MAP = {
  blue:   { light: '#1f4ed8', dark: '#7b9bff', lightSoft: '#eaefff', darkSoft: '#1c2440' },
  indigo: { light: '#4338ca', dark: '#a5a0ff', lightSoft: '#ecebff', darkSoft: '#241f52' },
  teal:   { light: '#0d7377', dark: '#5ecfd4', lightSoft: '#e0f3f3', darkSoft: '#0f2e30' },
  amber:  { light: '#b45309', dark: '#f5b149', lightSoft: '#fdf1d8', darkSoft: '#3a2a0f' },
  rose:   { light: '#be185d', dark: '#ff8fb6', lightSoft: '#ffe7ee', darkSoft: '#3d1628' },
};

function applyTweaks(tw) {
  const root = document.documentElement;
  root.setAttribute('data-theme', tw.theme);
  const a = ACCENT_MAP[tw.accent] || ACCENT_MAP.blue;
  const isDark = tw.theme === 'dark';
  root.style.setProperty('--accent', isDark ? a.dark : a.light);
  root.style.setProperty('--accent-soft', isDark ? a.darkSoft : a.lightSoft);
}

function App() {
  const [tweaks, setTweaks] = useState(() => ({ ...window.TWEAKS }));
  const [query, setQuery] = useState('');
  const [tierFilter, setTierFilter] = useState('all');
  const [sortKey, setSortKey] = useState('tier');
  const [selected, setSelected] = useState(null);
  const [favs, setFavs] = useState(() => {
    try { return JSON.parse(localStorage.getItem('fav-models') || '[]'); } catch { return []; }
  });
  const [onlyFavs, setOnlyFavs] = useState(false);

  useEffect(() => { applyTweaks(tweaks); }, [tweaks]);
  useEffect(() => { localStorage.setItem('fav-models', JSON.stringify(favs)); }, [favs]);

  const updateTweak = (patch) => setTweaks(prev => ({ ...prev, ...patch }));

  const toggleFav = useCallback((id) => {
    setFavs(f => f.includes(id) ? f.filter(x => x !== id) : [...f, id]);
  }, []);

  const availableTiers = useMemo(() => {
    const counts = {};
    window.MODELS.forEach(m => { counts[m.tier] = (counts[m.tier] || 0) + 1; });
    return [
      { id: 'all',      label: 'すべて',   count: window.MODELS.length },
      { id: 'standard', label: 'Standard', count: counts.standard || 0 },
      { id: 'air',      label: 'Air',      count: counts.air || 0 },
      { id: 'pro',      label: 'Pro',      count: counts.pro || 0 },
      { id: 'max',      label: 'Pro Max',  count: counts.max || 0 },
    ].filter(t => t.id === 'all' || t.count > 0);
  }, []);

  const filtered = useMemo(() => {
    let list = window.MODELS.slice();
    if (onlyFavs) list = list.filter(m => favs.includes(m.id));
    if (tierFilter !== 'all') list = list.filter(m => m.tier === tierFilter);
    if (query.trim()) {
      const q = query.toLowerCase();
      list = list.filter(m => (m.model + ' ' + m.storage).toLowerCase().includes(q));
    }
    const tierOrder = { max: 0, pro: 1, standard: 2, air: 3 };
    const sorters = {
      'tier':       (a, b) => (tierOrder[a.tier] - tierOrder[b.tier]) || ((b.maxPrice || 0) - (a.maxPrice || 0)),
      'price-desc': (a, b) => (b.maxPrice || 0) - (a.maxPrice || 0),
      'price-asc':  (a, b) => (a.maxPrice || 0) - (b.maxPrice || 0),
      'delta-desc': (a, b) => b.deltaPct - a.deltaPct,
      'delta-asc':  (a, b) => a.deltaPct - b.deltaPct,
      'spread':     (a, b) => (b.spread || 0) - (a.spread || 0),
    };
    list.sort(sorters[sortKey] || sorters.tier);
    return list;
  }, [query, tierFilter, sortKey, onlyFavs, favs]);

  const totalValue = useMemo(() =>
    window.MODELS.reduce((s, m) => s + (m.maxPrice || 0), 0), []);

  return (
    <div style={{ minHeight: '100vh' }}>
      <Header totalValue={totalValue} modelCount={window.MODELS.length} siteCount={window.BUYBACK_SITES.length}/>

      {/* Sticky controls */}
      <div style={{
        position: 'sticky', top: 0, zIndex: 20,
        background: 'color-mix(in srgb, var(--bg) 85%, transparent)',
        backdropFilter: 'blur(12px)',
        borderBottom: '1px solid var(--border)',
      }}>
        <div style={{
          maxWidth: 1240, margin: '0 auto', padding: '14px 24px',
          display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap',
        }}>
          {/* Search */}
          <div style={{ position: 'relative', flex: '1 1 220px', maxWidth: 340 }}>
            <div style={{
              position: 'absolute', left: 12, top: '50%', transform: 'translateY(-50%)',
              color: 'var(--ink-4)', display: 'flex',
            }}><Icon.Search/></div>
            <input
              value={query}
              onChange={e => setQuery(e.target.value)}
              placeholder="機種名・容量で検索…"
              style={{
                width: '100%', padding: '10px 12px 10px 36px',
                background: 'var(--surface)',
                border: '1px solid var(--border)',
                borderRadius: 8, fontSize: 14, color: 'var(--ink)',
                outline: 'none', transition: 'border-color .15s',
              }}
              onFocus={e => e.target.style.borderColor = 'var(--accent)'}
              onBlur={e => e.target.style.borderColor = 'var(--border)'}
            />
          </div>

          {/* Tier filter */}
          <div style={{ display: 'flex', gap: 2, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 8, padding: 3 }}>
            {availableTiers.map(t => (
              <button key={t.id} onClick={() => setTierFilter(t.id)} style={{
                padding: '6px 11px', fontSize: 12, fontWeight: 500, borderRadius: 5,
                color: tierFilter === t.id ? 'var(--ink)' : 'var(--ink-3)',
                background: tierFilter === t.id ? 'var(--surface-2)' : 'transparent',
                boxShadow: tierFilter === t.id ? 'inset 0 0 0 1px var(--border)' : 'none',
                display: 'flex', alignItems: 'center', gap: 6,
              }}>
                {t.label}
                <span className="mono" style={{ fontSize: 10, color: 'var(--ink-4)' }}>{t.count}</span>
              </button>
            ))}
          </div>

          {/* Sort */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginLeft: 'auto' }}>
            <label style={{ fontSize: 12, color: 'var(--ink-3)', display: 'flex', alignItems: 'center', gap: 4 }}>
              <Icon.Sort/> 並替
            </label>
            <select value={sortKey} onChange={e => setSortKey(e.target.value)} style={{
              padding: '8px 10px', fontSize: 13, border: '1px solid var(--border)',
              borderRadius: 8, background: 'var(--surface)', color: 'var(--ink)',
              fontFamily: 'inherit', outline: 'none', cursor: 'pointer',
            }}>
              <option value="tier">デフォルト（モデル順）</option>
              <option value="price-desc">価格: 高い順</option>
              <option value="price-asc">価格: 安い順</option>
              <option value="delta-desc">前日比: 上昇順</option>
              <option value="delta-asc">前日比: 下落順</option>
              <option value="spread">価格差: 大きい順</option>
            </select>
          </div>

          {/* Fav toggle */}
          <button onClick={() => setOnlyFavs(v => !v)} style={{
            padding: '8px 12px', fontSize: 12, fontWeight: 500,
            border: '1px solid var(--border)', borderRadius: 8,
            background: onlyFavs ? 'var(--accent-soft)' : 'var(--surface)',
            color: onlyFavs ? 'var(--accent)' : 'var(--ink-2)',
            display: 'flex', alignItems: 'center', gap: 6,
          }}>
            {onlyFavs ? <Icon.Star/> : <Icon.StarOutline/>}
            お気に入り {favs.length > 0 && <span className="mono" style={{ fontSize: 10, opacity: 0.7 }}>{favs.length}</span>}
          </button>

          {/* Layout toggle */}
          <div style={{ display: 'flex', gap: 2, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 8, padding: 3 }}>
            {['grid', 'table'].map(l => (
              <button key={l} onClick={() => updateTweak({ layout: l })} style={{
                padding: '6px 10px', fontSize: 12, borderRadius: 5,
                color: tweaks.layout === l ? 'var(--ink)' : 'var(--ink-3)',
                background: tweaks.layout === l ? 'var(--surface-2)' : 'transparent',
                boxShadow: tweaks.layout === l ? 'inset 0 0 0 1px var(--border)' : 'none',
              }}>{l === 'grid' ? 'カード' : 'テーブル'}</button>
            ))}
          </div>

          {/* Dark mode toggle */}
          <button
            onClick={() => updateTweak({ theme: tweaks.theme === 'dark' ? 'light' : 'dark' })}
            title={tweaks.theme === 'dark' ? 'ライトモード' : 'ダークモード'}
            style={{
              padding: '8px 10px', border: '1px solid var(--border)', borderRadius: 8,
              background: 'var(--surface)', color: 'var(--ink-2)', display: 'flex', alignItems: 'center',
            }}
          >
            {tweaks.theme === 'dark' ? <Icon.Sun/> : <Icon.Moon/>}
          </button>
        </div>
      </div>

      {/* Content */}
      <main style={{ maxWidth: 1240, margin: '0 auto', padding: '24px' }}>
        {filtered.length === 0 ? (
          <EmptyState/>
        ) : tweaks.layout === 'table' ? (
          <TableView models={filtered} onOpen={setSelected} favs={favs} onToggleFav={toggleFav}/>
        ) : (
          <GridView models={filtered} onOpen={setSelected} favs={favs} onToggleFav={toggleFav} density={tweaks.density}/>
        )}
      </main>

      <Footer/>

      {selected && <DetailModal model={selected} onClose={() => setSelected(null)}/>}
    </div>
  );
}

function Header({ totalValue, modelCount, siteCount }) {
  return (
    <header style={{ borderBottom: '1px solid var(--border)', background: 'var(--surface)' }}>
      <div style={{ maxWidth: 1240, margin: '0 auto', padding: '28px 24px 24px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 20, flexWrap: 'wrap' }}>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, color: 'var(--accent)', marginBottom: 10 }}>
              <Icon.Logo/>
              <span style={{ fontWeight: 600, fontSize: 13, letterSpacing: 0.2 }}>iPhone17 買取比較</span>
            </div>
            <h1 style={{ margin: 0, fontSize: 32, fontWeight: 700, letterSpacing: '-0.03em', color: 'var(--ink)', lineHeight: 1.1 }}>
              iPhone 17 シリーズ <span style={{ color: 'var(--ink-3)', fontWeight: 500 }}>買取価格比較</span>
            </h1>
            <p style={{ margin: '8px 0 0', color: 'var(--ink-3)', fontSize: 14, maxWidth: 560 }}>
              主要買取サイトの最新買取上限額を自動収集して比較。あなたの端末を最も高く売れるサイトが一目でわかります。
            </p>
          </div>

          <div style={{
            display: 'flex', gap: 0,
            border: '1px solid var(--border)', borderRadius: 10,
            background: 'var(--surface-2)', overflow: 'hidden',
          }}>
            <HeaderStat label="モデル" value={modelCount}/>
            <HeaderStat label="比較サイト" value={siteCount}/>
            <HeaderStat label="最高値合計" value={totalValue > 0 ? fmtYen(totalValue) : '取得中'} wide/>
          </div>
        </div>

        <div style={{ marginTop: 18, display: 'flex', alignItems: 'center', gap: 10, fontSize: 11, color: 'var(--ink-4)' }}>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
            <span style={{
              width: 6, height: 6, borderRadius: '50%',
              background: 'var(--up)', boxShadow: '0 0 0 3px color-mix(in srgb, var(--up) 20%, transparent)',
              animation: 'pulse 2s ease-in-out infinite',
            }}/>
            <span className="mono">AUTO</span>
          </span>
          <span style={{ color: 'var(--border-strong)' }}>·</span>
          <span className="mono">最終更新: {window.LAST_UPDATED}</span>
        </div>
      </div>
    </header>
  );
}

function HeaderStat({ label, value, wide }) {
  return (
    <div style={{
      padding: '12px 18px',
      borderRight: wide ? 'none' : '1px solid var(--border)',
      minWidth: wide ? 160 : 90,
    }}>
      <div style={{ fontSize: 10, color: 'var(--ink-4)', fontWeight: 600, letterSpacing: 0.5, textTransform: 'uppercase' }}>{label}</div>
      <div className="mono" style={{ marginTop: 2, fontSize: 17, fontWeight: 600, color: 'var(--ink)', letterSpacing: '-0.01em' }}>
        {value}
      </div>
    </div>
  );
}

function GridView({ models, onOpen, favs, onToggleFav, density }) {
  return (
    <div style={{
      display: 'grid',
      gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
      gap: 14,
    }}>
      {models.map(m => (
        <PriceCard key={m.id} m={m} onOpen={onOpen}
          favorited={favs.includes(m.id)}
          onToggleFav={onToggleFav}
          density={density}/>
      ))}
    </div>
  );
}

function TableView({ models, onOpen, favs, onToggleFav }) {
  return (
    <div style={{
      background: 'var(--surface)',
      border: '1px solid var(--border)',
      borderRadius: 12,
      overflow: 'hidden',
      boxShadow: 'var(--shadow)',
    }}>
      <div style={{ overflowX: 'auto' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 880 }}>
          <thead>
            <tr style={{ borderBottom: '1px solid var(--border)', background: 'var(--surface-2)' }}>
              <Th style={{ width: 32 }}></Th>
              <Th>モデル</Th>
              <Th align="right">最高値</Th>
              <Th align="right">前日比</Th>
              <Th>最高値サイト</Th>
              <Th align="right">比較数</Th>
              <Th align="right">価格差</Th>
              <Th>分布</Th>
            </tr>
          </thead>
          <tbody>
            {models.map(m => (
              <PriceRow key={m.id} m={m} onOpen={onOpen}
                favorited={favs.includes(m.id)}
                onToggleFav={onToggleFav}/>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function Th({ children, align, style }) {
  return (
    <th style={{
      padding: '12px 12px', textAlign: align || 'left',
      fontSize: 10, fontWeight: 600, letterSpacing: 0.5, textTransform: 'uppercase',
      color: 'var(--ink-3)', ...style,
    }}>{children}</th>
  );
}

function EmptyState() {
  return (
    <div style={{
      padding: 80, textAlign: 'center',
      border: '1px dashed var(--border-strong)',
      borderRadius: 12, background: 'var(--surface)',
    }}>
      <div style={{ fontSize: 40, color: 'var(--ink-4)', marginBottom: 12 }}>∅</div>
      <div style={{ fontSize: 15, fontWeight: 500, color: 'var(--ink-2)' }}>該当する機種が見つかりませんでした</div>
      <div style={{ fontSize: 13, color: 'var(--ink-3)', marginTop: 4 }}>検索条件を変更してお試しください</div>
    </div>
  );
}

function Footer() {
  return (
    <footer style={{
      borderTop: '1px solid var(--border)',
      padding: '28px 24px 40px',
      marginTop: 60,
    }}>
      <div style={{ maxWidth: 1240, margin: '0 auto', display: 'flex', justifyContent: 'space-between', gap: 20, flexWrap: 'wrap', fontSize: 12, color: 'var(--ink-3)' }}>
        <div>
          <div style={{ fontWeight: 600, color: 'var(--ink-2)', marginBottom: 6 }}>iPhone17 買取比較</div>
          <div>買取価格は各社公表の上限額です。実査定額は端末の状態により変動します。</div>
        </div>
        <div style={{ display: 'flex', gap: 24 }}>
          <div>
            <div style={{ fontWeight: 600, color: 'var(--ink-2)', marginBottom: 6 }}>対応サイト</div>
            <div className="mono">{window.BUYBACK_SITES.length} 社</div>
          </div>
          <div>
            <div style={{ fontWeight: 600, color: 'var(--ink-2)', marginBottom: 6 }}>更新頻度</div>
            <div>1日1回（自動）</div>
          </div>
        </div>
      </div>
    </footer>
  );
}

// ---------- Global keyframes ----------
(function injectKF() {
  const css = `
    @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
    @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
  `;
  const s = document.createElement('style'); s.textContent = css; document.head.appendChild(s);
})();

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