// Market — ПЛОСКАЯ лента реальных NFT-подарков (отдельные NFT, не категории):
// по умолчанию самые дёшевые по всему маркету (useMarketFeed). Выбор коллекции в
// фильтрах → её листинги (useGifts). Модель/Фон/Символ — только при 1 коллекции.
// Данные через window.DataSource. Картинка карточки = реальное photo_url NFT (с фоном).

// Add-to-cart button. Tap to add; once in the cart it shows a green check —
// press & hold ~0.5s (a sweeping ring fills) to remove it from the cart.
function AddCartButton({ inCart, onAdd, onRemove }) {
  const [holding, setHolding] = React.useState(false);
  const timer = React.useRef(0);
  const fired = React.useRef(false);

  const start = (e) => {
    e.stopPropagation();
    fired.current = false;
    if (!inCart) return;
    setHolding(true);
    clearTimeout(timer.current);
    timer.current = setTimeout(() => {
      fired.current = true;
      setHolding(false);
      onRemove();
      if (navigator.vibrate) navigator.vibrate(25);
    }, 500);
  };
  const cancel = () => { clearTimeout(timer.current); setHolding(false); };
  const click = (e) => {
    e.stopPropagation();
    if (inCart || fired.current) return; // in cart → use long-press to remove
    onAdd();
  };
  React.useEffect(() => () => clearTimeout(timer.current), []);

  return (
    <button onClick={click}
            onPointerDown={start} onPointerUp={cancel}
            onPointerLeave={cancel} onPointerCancel={cancel}
            aria-label={inCart ? 'Удерживайте, чтобы убрать' : 'В корзину'}
            className={'add-btn' + (holding ? ' holding' : '')}
            style={{
              position: 'relative',
              cursor: 'pointer',
              background: inCart ? 'var(--green-soft)' : 'var(--accent-soft)',
              color: inCart ? 'var(--green)' : 'var(--accent)',
              touchAction: 'none',
            }}>
      {inCart ? <Icons.check size={18}/> : <Icons.plus size={18}/>}
      {holding && (
        <svg className="hold-ring" viewBox="0 0 46 46" width="46" height="46">
          <circle cx="23" cy="23" r="19" fill="none"
                  stroke="var(--red)" strokeWidth="3" strokeLinecap="round"
                  strokeDasharray="119" strokeDashoffset="119"/>
        </svg>
      )}
    </button>
  );
}

function GiftCard({ listing, onClick, onAddToCart, onRemoveFromCart, inCart, idx = 0 }) {
  return (
    <div className="card-press gift-card" onClick={onClick}
         style={{
           display: 'flex', flexDirection: 'column',
           gap: 8, cursor: 'pointer',
           animation: `fadeUp 0.4s ${Math.min(idx * 0.028, 0.32)}s both`,
         }}>
      <div className="gift-card-media"
           style={{ boxShadow: 'inset 0 0 0 1px var(--border)' }}>
        <GiftMedia kind={listing.kind} num={listing.num} rounded={22} photo={listing.photo}/>
        {/* Реальная скидка от floor коллекции — зелёный бейдж */}
        {(Number(listing.discount_pct) || 0) >= 1 && (
          <div style={{
            position: 'absolute', top: 8, left: 8, zIndex: 2,
            padding: '2px 7px', borderRadius: 999,
            background: 'var(--green)', color: '#fff',
            fontSize: 10, fontWeight: 800, letterSpacing: '0.01em',
            boxShadow: '0 2px 8px rgba(0,0,0,0.35)',
          }}>−{Math.round(listing.discount_pct)}%</div>
        )}
        {listing.num != null && (
          <div style={{
            position: 'absolute', bottom: 8, right: 10, zIndex: 2,
            fontSize: 11, fontWeight: 700, color: 'rgba(255,255,255,0.96)',
            letterSpacing: '-0.005em',
            textShadow: '0 1px 3px rgba(0,0,0,0.6)',
          }}>#{listing.num}</div>
        )}
      </div>
      <div className="col gap-2" style={{ padding: '0 4px' }}>
        <div style={{
          fontSize: 13, fontWeight: 650, letterSpacing: '-0.01em',
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>{listing.name}</div>
        <div className="row aic gap-8" style={{ marginTop: 2 }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 15, fontWeight: 700, letterSpacing: '-0.01em' }}>
              {fmtRub(listing.rub)}
            </div>
            {listing.ton > 0 && (
              <div className="small t-mute mono" style={{ fontSize: 10.5, marginTop: 1 }}>
                {listing.ton} TON
              </div>
            )}
          </div>
          {onAddToCart && (
            <AddCartButton inCart={inCart}
                           onAdd={() => onAddToCart(listing)}
                           onRemove={() => onRemoveFromCart && onRemoveFromCart(listing.id)}/>
          )}
        </div>
      </div>
    </div>
  );
}

// Скелетон-плитка на время загрузки.
function CardSkeleton({ idx = 0 }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8,
                  animation: `fadeUp 0.4s ${Math.min(idx * 0.03, 0.3)}s both` }}>
      <div className="skeleton" style={{ width: '100%', aspectRatio: '1/1', borderRadius: 22 }}/>
      <div className="skeleton" style={{ width: '70%', height: 12, borderRadius: 6, margin: '0 4px' }}/>
      <div className="skeleton" style={{ width: '40%', height: 14, borderRadius: 6, margin: '0 4px' }}/>
    </div>
  );
}

// Кольцевой лоадер ожидания (CSS .mp-spinner). small — для подгрузки внутри ленты
// (горизонтально, компактно). Большой — по центру области, текст ПОД спиннером.
function Spinner({ small = false, label }) {
  if (small) {
    return (
      <div className="row aic" style={{ justifyContent: 'center', gap: 10, padding: '6px 0 2px' }}>
        <div className="mp-spinner sm"/>
        {label && <span className="small t-soft">{label}</span>}
      </div>
    );
  }
  return (
    <div className="col aic" style={{
      alignItems: 'center', justifyContent: 'center', textAlign: 'center',
      gap: 16, minHeight: 320, padding: '24px 16px',
    }}>
      <div className="mp-spinner"/>
      {label && <span className="t-soft">{label}</span>}
    </div>
  );
}

function MarketScreen({ onGift, onAddToCart, onRemoveFromCart, cart, advFilters, openFilters, hiddenIds }) {
  const PAGE_SIZE = 50;
  const BUFFER_PAGES = 2;   // запас ~3 страницы вперёд (каждая = неск. Portals-поисков ~5с, не жадничаем)
  const hidden = hiddenIds || new Set();
  const DS = window.DataSource || {};

  const [sort, setSort] = React.useState('feed');   // feed = по возрастанию цены (лента)
  const [query, setQuery] = React.useState('');
  const [page, setPage] = React.useState(1);

  // Коллекция выбрана (ровно одна) → режим коллекции; иначе → общая лента.
  // Имя резолвим по живой карте /collections (канонично для Portals), фоллбэк — хардкод GIFT_KINDS.
  const slug = advFilters.collection.length === 1 ? advFilters.collection[0] : null;
  const collectionName = slug
    ? ((window.__COLLECTION_NAMES && window.__COLLECTION_NAMES[slug])
        || (window.GIFT_KINDS[slug] && window.GIFT_KINDS[slug].name) || null)
    : null;

  const apiSort = sort === 'price-desc' ? 'price_desc' : 'price_asc';
  const csv = (a) => Array.isArray(a) ? a.join(',') : (a || '');
  const advKey = JSON.stringify(advFilters);

  // Оба хука вызываются ВСЕГДА (правила хуков); реально грузит лишь активный:
  //   feed — когда коллекция НЕ выбрана; gifts — когда выбрана.
  const feed = DS.useMarketFeed ? DS.useMarketFeed({ enabled: !collectionName })
                                : { items: [], loading: false, hasMore: false, error: null, loadMore: () => {} };
  const gifts = DS.useGifts ? DS.useGifts({
    gift: collectionName || '',
    model: csv(advFilters.model), backdrop: csv(advFilters.backdrop), symbol: csv(advFilters.symbol),
    sort: apiSort,
  }) : { items: [], loading: false, hasMore: false, error: null, loadMore: () => {} };

  const active = collectionName ? gifts : feed;

  // Сброс на 1-ю страницу при смене контекста.
  React.useEffect(() => { setPage(1); }, [collectionName, sort, advKey, query]);

  // Догружаем С ЗАПАСОМ (~BUFFER_PAGES страниц вперёд), чтобы «Дальше» открывалась без ожидания.
  React.useEffect(() => {
    const target = (page + BUFFER_PAGES) * PAGE_SIZE;
    if (active.items.length < target && active.hasMore && !active.loading) active.loadMore();
  }, [page, collectionName, active.items.length, active.hasMore, active.loading]);

  const q = query.toLowerCase().trim();
  let visible = active.items.filter(l => !(hidden.has && hidden.has(l.id)));
  // 2+ коллекций: бэк per-collection не умеет — фильтруем ленту клиентски по слагам.
  if (!collectionName && advFilters.collection.length > 1) {
    visible = visible.filter(l => advFilters.collection.includes(l.kind));
  }
  if (q) visible = visible.filter(l => (l.name || '').toLowerCase().includes(q) || String(l.num || '').includes(q));
  // Сортируем ВЕСЬ загруженный пул до нарезки страниц (не только текущую страницу).
  if (sort !== 'feed') {
    visible = visible.slice().sort((a, b) => sort === 'price-asc' ? a.rub - b.rub : b.rub - a.rub);
  }

  const pageItems = visible.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);
  const hasNext = (!q && active.hasMore) || visible.length > page * PAGE_SIZE;
  const advCount = Object.values(advFilters).reduce((s, a) => s + (a ? a.length : 0), 0);

  const goPage = (p) => {
    if (p < 1) return;
    setPage(p);
    if (window.SFX) window.SFX.click();
    document.querySelectorAll('.screen-scroll').forEach(el => { el.scrollTop = 0; });
  };
  const cycleSort = () => {
    setSort(s => s === 'feed' ? 'price-desc' : s === 'price-desc' ? 'price-asc' : 'feed');
    if (window.SFX) window.SFX.click();
  };

  const ToolBtn = ({ children, onClick, badge }) => (
    <button onClick={onClick} style={{
      width: 38, height: 38, borderRadius: '50%', border: 0, padding: 0, cursor: 'pointer',
      background: 'var(--bg-input)', color: 'var(--text)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      position: 'relative', flexShrink: 0,
    }}>
      {children}
      {badge != null && badge > 0 && (
        <span style={{
          position: 'absolute', top: -3, right: -3, minWidth: 16, height: 16, padding: '0 4px',
          borderRadius: 999, background: 'var(--accent)', color: '#fff',
          fontSize: 10, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center',
          border: '1.5px solid var(--bg-app)',
        }}>{badge}</span>
      )}
    </button>
  );

  // Чип категории фильтра. Модель/Фон/Символ — атрибуты экземпляра, доступны
  // только когда выбрана ровно одна коллекция.
  const CategoryChip = ({ tab, label }) => {
    const n = advFilters[tab]?.length || 0;
    const on = n > 0;
    const locked = tab !== 'collection' && advFilters.collection.length !== 1;
    return (
      // locked-чип НЕ дизейблим: на таче title-тултип не работает — по тапу ведём
      // юзера сразу в выбор коллекции.
      <button onClick={() => { openFilters(locked ? 'collection' : tab); }}
              title={locked ? 'Выберите ровно одну коллекцию' : undefined}
              style={{
        display: 'inline-flex', alignItems: 'center', gap: 6,
        padding: '8px 14px', borderRadius: 999, border: 0,
        cursor: locked ? 'not-allowed' : 'pointer',
        background: on ? 'var(--accent)' : 'var(--bg-input)',
        color: on ? '#fff' : 'var(--text)',
        fontSize: 13, fontWeight: 600, whiteSpace: 'nowrap', flexShrink: 0,
        boxShadow: on ? '0 4px 12px var(--accent-glow)' : 'none',
        opacity: locked ? 0.4 : 1,
        transition: 'background 0.15s, color 0.15s, opacity 0.15s',
      }}>
        {locked && Icons.lock && <Icons.lock size={11} style={{ opacity: 0.7 }}/>}
        <span>{label}</span>
        <Icons.chevD size={12} style={{ opacity: 0.75 }}/>
        {n > 0 && (
          <span style={{
            background: 'rgba(255,255,255,0.25)', color: '#fff',
            minWidth: 16, height: 16, padding: '0 4px', borderRadius: 999,
            fontSize: 10, fontWeight: 700, marginLeft: 2,
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          }}>{n}</span>
        )}
      </button>
    );
  };

  return (
    <ScreenWrap>
      <GlassCard style={{ padding: '8px 12px', paddingRight: (cart && cart.length ? 64 : 12) }}>
        <div className="row aic gap-8">
          <Icons.search size={18} style={{ color: 'var(--text-mute)' }}/>
          <input className="input" placeholder="Поиск по названию или #номеру..."
                 value={query} onChange={(e) => setQuery(e.target.value)}
                 style={{ background: 'transparent', padding: '6px 0', flex: 1, fontSize: 14 }}/>
        </div>
      </GlassCard>

      {/* Toolbar: фильтр + сортировка + категории. Верт. padding — чтобы бейдж счётчика
          (top:-3) не обрезался горизонтальным overflow. */}
      <div style={{ display: 'flex', gap: 8, overflowX: 'auto', scrollbarWidth: 'none', alignItems: 'center', padding: '6px 2px' }}>
        <ToolBtn onClick={() => openFilters('collection')} badge={advCount}>
          <Icons.filter size={15}/>
        </ToolBtn>
        <ToolBtn onClick={cycleSort}>
          {sort === 'feed' ? <Icons.bolt size={15}/> : sort === 'price-desc' ? <Icons.arrowDown size={15}/> : <Icons.arrowUp size={15}/>}
        </ToolBtn>
        <CategoryChip tab="collection" label="Коллекция"/>
        <CategoryChip tab="model"      label="Модель"/>
        <CategoryChip tab="backdrop"   label="Фон"/>
        <CategoryChip tab="symbol"     label="Символ"/>
      </div>

      <div className="row aic jcsb" style={{ padding: '0 4px' }}>
        <div className="lbl">
          {collectionName ? collectionName : 'Все подарки'}{pageItems.length ? ` · стр. ${page}` : ''}
        </div>
        <div className="small t-soft row aic gap-4">
          <Icons.dot size={8} style={{ color: 'var(--green)' }}/>
          {sort === 'feed' ? (collectionName ? 'дешёвые первыми' : 'самые дешёвые') : sort === 'price-desc' ? 'сначала дорогие' : 'сначала дешёвые'}
        </div>
      </div>

      {(pageItems.length === 0 && !active.error && (active.loading || (active.hasMore && !q))) ? (
        <Spinner label="Загружаю подарки..."/>
      ) : active.error && pageItems.length === 0 ? (
        <div className="col aic" style={{ alignItems: 'center', textAlign: 'center', padding: '32px 16px', gap: 12 }}>
          <div style={{ fontSize: 17, fontWeight: 700 }}>Маркет прилёг отдохнуть</div>
          <div className="t-soft body" style={{ maxWidth: 260 }}>
            {window.friendlyError ? window.friendlyError(active.error, 'market') : 'К сожалению, маркет сейчас недоступен — попробуй через минуту'}
          </div>
          <button onClick={() => active.loadMore()} style={{
            padding: '12px 22px', borderRadius: 999, background: 'var(--accent)', color: '#fff',
            border: 0, cursor: 'pointer', fontSize: 14, fontWeight: 650,
            display: 'inline-flex', alignItems: 'center', gap: 8,
            boxShadow: '0 6px 18px var(--accent-glow)',
          }}><Icons.refresh size={14}/> Повторить</button>
        </div>
      ) : !pageItems.length ? (
        <div className="col aic" style={{
          alignItems: 'center', textAlign: 'center', padding: '24px 16px 32px', gap: 18,
        }}>
          <div style={{
            width: 156, height: 156, borderRadius: 28, overflow: 'hidden', position: 'relative',
            background: 'var(--bg-input)', display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}>
            <img src="https://nft.fragment.com/gift/PlushPepe-1.medium.jpg" alt=""
                 style={{ width: '88%', height: '88%', objectFit: 'contain',
                          filter: 'grayscale(1) brightness(0.85) opacity(0.55)' }}/>
          </div>
          <div className="col gap-6" style={{ alignItems: 'center', maxWidth: 260 }}>
            <div style={{ fontSize: 17, fontWeight: 700, letterSpacing: '-0.01em' }}>Ничего не нашлось</div>
            <div className="t-soft body" style={{ lineHeight: 1.4 }}>
              {collectionName ? 'В этой коллекции нет подарков под фильтры.' : 'Попробуй убрать часть фильтров или поиск.'}
            </div>
          </div>
          {(advCount > 0 || query) && (
            <button onClick={() => { openFilters('__reset'); setQuery(''); }} style={{
              padding: '12px 22px', borderRadius: 999, background: 'var(--accent)', color: '#fff',
              border: 0, cursor: 'pointer', fontSize: 14, fontWeight: 650,
              display: 'inline-flex', alignItems: 'center', gap: 8,
              boxShadow: '0 6px 18px var(--accent-glow)',
            }}>
              <Icons.refresh size={14}/> Очистить фильтры
            </button>
          )}
        </div>
      ) : (
        <>
        <div key={page} className="anim-fade-up" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          {pageItems.map((l, i) => (
            <GiftCard key={l.id} listing={l} idx={i}
                      onClick={() => onGift(l)}
                      onAddToCart={onAddToCart}
                      onRemoveFromCart={onRemoveFromCart}
                      inCart={cart?.some(x => x.id === l.id)}/>
          ))}
        </div>

        <div style={{ paddingTop: 10, paddingBottom: 20 }}>
          <div className="row aic" style={{ gap: 10 }}>
            <button className="card-press" onClick={() => goPage(page - 1)} disabled={page === 1} style={{
              flex: 1, height: 54, borderRadius: 16, border: 0,
              display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6,
              background: 'var(--bg-input)', color: 'var(--text)', fontSize: 15, fontWeight: 650,
              cursor: page === 1 ? 'default' : 'pointer', opacity: page === 1 ? 0.34 : 1,
              boxShadow: 'inset 0 0 0 0.5px var(--border)',
            }}>
              <Icons.chevL size={18}/> Назад
            </button>
            <div className="mono" style={{
              width: 54, height: 54, flexShrink: 0, borderRadius: 16,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              background: 'var(--accent-soft)', color: 'var(--accent)', fontSize: 20, fontWeight: 800,
            }}>{page}</div>
            <button className="card-press" onClick={() => goPage(page + 1)} disabled={!hasNext} style={{
              flex: 1, height: 54, borderRadius: 16, border: 0,
              display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6,
              background: hasNext ? 'linear-gradient(135deg, var(--accent), var(--accent-2))' : 'var(--bg-input)',
              color: hasNext ? '#fff' : 'var(--text-mute)', fontSize: 15, fontWeight: 700,
              cursor: hasNext ? 'pointer' : 'default',
              boxShadow: hasNext ? '0 8px 22px var(--accent-glow)' : 'none',
            }}>
              Дальше <Icons.chevR size={18}/>
            </button>
          </div>
        </div>
        </>
      )}
    </ScreenWrap>
  );
}

window.MarketScreen = MarketScreen;
window.GiftCard = GiftCard;
