// Purchase flow — РЕАЛЬНАЯ покупка: confirm → creating (POST /purchase) →
// awaiting (оплата + поллинг /me/orders/{id}) → success | error.
// Дизайн-экраны прежние (confirm-карточка, processing с баром, success с конфетти).

// Платёжные ссылки открываем только с доверенных хостов.
const _PAY_ALLOWED_HOSTS = ['platega.io', 'pay.platega.io', 'app.platega.io',
  'yookassa.ru', 'yoomoney.ru', 'robokassa.ru', 'auth.robokassa.ru',
  't.me', '127.0.0.1', 'localhost'];

function _openPayUrl(url) {
  const s = String(url || '');
  if (s.includes('/mock-pay/') || s === 'about:blank') return 'mock';  // dev-провайдер
  let parsed = null;
  try { parsed = new URL(s); } catch (_) { return 'blocked'; }
  const ok = (parsed.protocol === 'http:' || parsed.protocol === 'https:')
    && _PAY_ALLOWED_HOSTS.some(h => parsed.hostname === h || parsed.hostname.endsWith('.' + h));
  if (!ok) return 'blocked';
  const tg = window.Telegram && window.Telegram.WebApp;
  if (tg && tg.openLink) tg.openLink(s, { try_instant_view: false });
  else window.open(s, '_blank', 'noopener,noreferrer');
  return 'opened';
}

function PurchaseFlow({ gift, balance, onClose, onComplete, onSuccess }) {
  // confirm | creating | awaiting | success | error
  const [stage, setStage] = React.useState('confirm');
  const [note, setNote] = React.useState('');
  const [error, setError] = React.useState(null);
  const [quote, setQuote] = React.useState(null);   // серверная цена перед оплатой
  const pollRef = React.useRef({ stop: false });
  React.useEffect(() => () => { pollRef.current.stop = true; }, []);

  // Авторитетная цена с бэка (POST /buy/quote) на экране подтверждения: показываем
  // ровно то, что спишем, и передаём свежий ton в expected_price_ton — так покупка
  // не спотыкается о 409 «цена выросла» из-за устаревшего кеша ленты.
  React.useEffect(() => {
    if (stage !== 'confirm' || !gift || gift.num == null) return;
    const DS = window.DataSource;
    if (!DS || !DS.getQuote) return;
    let cancel = false;
    DS.getQuote(gift.name, gift.num).then(q => { if (!cancel) setQuote(q); }).catch(() => {});
    return () => { cancel = true; };
  }, [stage, gift]);
  const billRub = (quote && quote.price_rub) ? quote.price_rub : (gift ? gift.rub : 0);

  // Поллинг заказа: каждые 4с до 10 минут.
  const pollOrder = React.useCallback(async (orderId) => {
    const DS = window.DataSource;
    const deadline = Date.now() + 10 * 60 * 1000;
    while (!pollRef.current.stop && Date.now() < deadline) {
      await new Promise(r => setTimeout(r, 4000));
      if (pollRef.current.stop) return;
      let o = null;
      try { o = await DS.getOrder(orderId); } catch (_) { continue; }  // сеть моргнула — повтор
      if (o.status === 'success') { setStage('success'); return; }
      if (o.status === 'failed') {
        try { console.warn('[purchase] order failed:', o.error_msg); } catch (_) {}
        setError({ kind: 'order_failed' });
        setStage('error');
        return;
      }
      setNote(o.status === 'processing' ? 'Оплата получена, выдаём подарок…' : 'Ждём подтверждения оплаты…');
    }
    if (!pollRef.current.stop) setNote('Оплата ещё обрабатывается. Подарок появится в «Моих подарках».');
  }, []);

  const startPurchase = React.useCallback(async () => {
    const DS = window.DataSource;
    try { window.Telegram?.WebApp?.HapticFeedback?.impactOccurred('medium'); } catch (_) {}
    setError(null);
    if (!DS || !DS.purchase) {
      // Прод в Telegram без DataSource — НЕ имитируем успех (иначе «куплено» без покупки).
      if (window.Telegram && window.Telegram.WebApp && window.Telegram.WebApp.initData) {
        setError({ kind: 'server' }); setStage('error'); return;
      }
      setStage('awaiting');                          // дизайн-симулятор в браузере
      setTimeout(() => setStage('success'), 1800);
      return;
    }
    setStage('creating');
    try {
      // Оплата с внутреннего ₽-баланса: бэк списывает и сразу ставит заказ в
      // processing (invoice_url пустой) → сразу поллим статус, без платёжки.
      // Свежий ton из quote (если получен) → expected_price_ton совпадает с бэком.
      const inv = await DS.purchase(quote ? { ...gift, ton: quote.price_ton } : gift, true);
      setStage('awaiting');
      setNote('Оплачено с баланса, выдаём подарок…');
      pollOrder(inv.order_id);
    } catch (e) {
      setError(e);           // 402 «недостаточно средств» покажется человеческим текстом
      setStage('error');
    }
  }, [gift, quote, pollOrder]);   // quote в deps: иначе замыкание держит stale null и цена не подхватывается

  // onSuccess строго один раз и ТОЛЬКО на реальном success.
  const successCalledRef = React.useRef(false);
  React.useEffect(() => {
    if (stage === 'success' && !successCalledRef.current && typeof onSuccess === 'function') {
      successCalledRef.current = true;
      onSuccess();
      try { window.Telegram?.WebApp?.HapticFeedback?.notificationOccurred('success'); } catch (_) {}
      if (window.SFX) window.SFX.success();
    }
    if (stage === 'error') {
      try { window.Telegram?.WebApp?.HapticFeedback?.notificationOccurred('error'); } catch (_) {}
    }
  }, [stage, onSuccess]);

  if (!gift) return null;
  const isRare = gift.tier === 'epic' || gift.tier === 'legendary';

  const errText = !error ? ''
    : error.kind === 'order_failed' ? 'Оплата не прошла или заказ отменён — деньги вернулись на баланс.'
    : (window.friendlyError ? window.friendlyError(error, 'purchase') : 'К сожалению, маркет сейчас недоступен — попробуй через минуту');

  return (
    <SheetShell onClose={onClose} dismissable={stage !== 'creating'}>

        {stage === 'confirm' && (
          <div className="col aic" style={{ alignItems: 'center', textAlign: 'center', padding: '4px 8px 8px' }}>
            <Gift kind={gift.kind} num={gift.num} size="xl" glow={isRare}/>
            <div className="row aic gap-6" style={{ marginTop: 12 }}>
              {gift.num != null && <div className="mono small t-mute">#{gift.num}</div>}
            </div>
            <div className="h2" style={{ marginTop: 2 }}>{gift.name}</div>

            <div style={{
              padding: '14px 16px', borderRadius: 14,
              alignSelf: 'stretch', marginTop: 16,
              background: 'var(--bg-input)',
              border: '0.5px solid var(--border)',
            }}>
              <div className="row aic jcsb">
                <div className="small t-soft">К оплате</div>
                <div className="mono" style={{ fontSize: 22, fontWeight: 700 }}>{fmtRub(billRub)}</div>
              </div>
              <div style={{ height: 0.5, background: 'var(--border)', margin: '10px 0' }}/>
              <div className="row aic jcsb">
                <div className="small t-soft">Модель</div>
                <div className="mono small" style={{ fontWeight: 600 }}>{(gift.attrs && gift.attrs.model && gift.attrs.model.name) || '—'}</div>
              </div>
              <div className="row aic jcsb" style={{ marginTop: 6 }}>
                <div className="small t-soft">Фон</div>
                <div className="mono small" style={{ fontWeight: 600 }}>{(gift.attrs && gift.attrs.backdrop && gift.attrs.backdrop.name) || '—'}</div>
              </div>
            </div>

            <button className="btn btn-primary center" style={{
              justifyContent: 'center', padding: '15px',
              alignSelf: 'stretch', marginTop: 16,
              fontSize: 16, fontWeight: 650,
            }} onClick={startPurchase}>
              <Icons.check size={17}/> Подтвердить покупку
            </button>
            <WithSheetClose>{close => (
              <button onClick={close} style={{
                border: 0, background: 'transparent', color: 'var(--text-soft)',
                padding: '10px', marginTop: 4, fontSize: 14, cursor: 'pointer',
              }}>Отменить</button>
            )}</WithSheetClose>
          </div>
        )}

        {(stage === 'creating' || stage === 'awaiting') && (
          <div className="col aic" style={{ alignItems: 'center', textAlign: 'center', padding: '36px 16px 28px' }}>
            <div className="anim-hero-float">
              <Gift kind={gift.kind} num={gift.num} size="2xl" animated clean glow/>
            </div>
            <div className="h2" style={{ marginTop: 24 }}>
              {stage === 'creating' ? 'Создаём счёт…' : 'Оплачиваем покупку…'}
            </div>
            <div className="t-soft body" style={{ marginTop: 6 }}>
              {stage === 'creating' ? 'Связываемся с Portals API' : (note || 'Ждём подтверждения оплаты…')}
            </div>
            <div className="bar" style={{ alignSelf: 'stretch', marginTop: 22 }}>
              <div style={{ width: '100%', animation: 'fillBar 1.8s cubic-bezier(0.4, 0, 0.2, 1) infinite' }}/>
            </div>
            {stage === 'awaiting' && (
              <WithSheetClose>{close => (
                <button onClick={close} style={{
                  border: 0, background: 'transparent', color: 'var(--text-soft)',
                  padding: '10px', marginTop: 14, fontSize: 14, cursor: 'pointer',
                }}>Свернуть — подарок придёт в «Мои»</button>
              )}</WithSheetClose>
            )}
          </div>
        )}

        {stage === 'error' && (
          <div className="col aic" style={{ alignItems: 'center', textAlign: 'center', padding: '28px 16px 8px' }}>
            <Gift kind={gift.kind} num={gift.num} size="xl"/>
            <div className="h2" style={{ marginTop: 20, color: 'var(--red, #e25555)' }}>Не получилось</div>
            <div className="t-soft body" style={{ marginTop: 6, maxWidth: 280 }}>{errText}</div>
            <div className="col gap-8" style={{ alignSelf: 'stretch', marginTop: 22 }}>
              <button className="btn btn-primary center" style={{
                justifyContent: 'center', padding: '14px', fontSize: 15, fontWeight: 650,
              }} onClick={() => { setError(null); setStage('confirm'); }}>
                <Icons.refresh size={16}/> Попробовать ещё раз
              </button>
              <WithSheetClose>{close => (
                <button className="btn center" style={{
                  justifyContent: 'center', padding: '12px', fontSize: 14,
                }} onClick={close}>Закрыть</button>
              )}</WithSheetClose>
            </div>
          </div>
        )}

        {stage === 'success' && (
          <div className="col aic" style={{
            alignItems: 'center', textAlign: 'center',
            padding: '28px 16px 8px', position: 'relative',
          }}>
            <Confetti/>
            <div className="anim-hero-float" style={{ position: 'relative', zIndex: 1 }}>
              <Gift kind={gift.kind} num={gift.num} size="2xl" animated clean glow/>
            </div>
            <div className="h2" style={{ marginTop: 22, color: 'var(--green)' }}>Подарок твой! 🎉</div>
            <div className="t-soft body" style={{ marginTop: 6, maxWidth: 280 }}>
              {gift.name}{gift.num != null ? ` #${gift.num}` : ''} добавлен в твою коллекцию. Можешь забрать его на свой Telegram-профиль или оставить здесь.
            </div>

            <div className="col gap-8" style={{ alignSelf: 'stretch', marginTop: 22 }}>
              <button className="btn btn-primary center" style={{
                justifyContent: 'center', padding: '14px', fontSize: 15, fontWeight: 650,
              }} onClick={() => onComplete(gift, 'goto')}>
                <Icons.download size={16}/> Забрать в Telegram
              </button>
              <button className="btn center" style={{
                justifyContent: 'center', padding: '12px', fontSize: 14,
              }} onClick={() => onComplete(gift, 'continue')}>
                Продолжить покупки
              </button>
            </div>
          </div>
        )}
    </SheetShell>
  );
}

window.PurchaseFlow = PurchaseFlow;
