// wizard.jsx — New reading order wizard

const WIZARD_STEPS = [
  { id: 'product', label: 'Продукт' },
  { id: 'person',  label: 'Персона' },
  { id: 'data',    label: 'Данные' },
  { id: 'pay',     label: 'Оплата' },
];

// Mapping наш UI-id → backend service-id.
const PRODUCT_TO_SERVICE = { natal: 'natal', forecast: 'year_ahead', compat: 'compatibility', matrix: 'matrix' };

// Конвертация "DD.MM.YYYY" → "YYYY-MM-DD" (формат, который ждёт бэкенд).
const dotDateToISO = (s) => {
  s = (s || '').trim();
  const m = s.match(/^(\d{1,2})[.\-/](\d{1,2})[.\-/](\d{4})$/);
  if (!m) return s; // оставим как есть, бэк сам ругнётся
  return `${m[3]}-${m[2].padStart(2,'0')}-${m[1].padStart(2,'0')}`;
};

// Маска даты: из любых символов оставляем цифры и расставляем точки ДД.ММ.ГГГГ
// по мере ввода. Бэкспейс работает естественно — точки убираются вместе с цифрами.
const maskDate = (s) => {
  const d = (s || '').replace(/\D/g, '').slice(0, 8);
  const parts = [];
  parts.push(d.slice(0, 2));
  if (d.length >= 3) parts.push(d.slice(2, 4));
  if (d.length >= 5) parts.push(d.slice(4, 8));
  return parts.filter(Boolean).join('.');
};

// Маска времени: цифры → чч:мм.
const maskTime = (s) => {
  const d = (s || '').replace(/\D/g, '').slice(0, 4);
  return d.length <= 2 ? d : d.slice(0, 2) + ':' + d.slice(2, 4);
};

// PlaceField — поле «место рождения» с автокомплитом от геокодера. Юзер выбирает
// конкретный город (одноимённые различаются) → onPick фиксирует lat/lng/tz, и
// бэкенд не геокодит свободный текст заново (без расползания данных).
const PlaceField = ({ value, onChange, onPick }) => {
  const [sugg, setSugg] = React.useState([]);
  const [open, setOpen] = React.useState(false);
  const tRef = React.useRef(null);
  const fetchSugg = (q) => {
    clearTimeout(tRef.current);
    if ((q || '').trim().length < 3) { setSugg([]); setOpen(false); return; }
    tRef.current = setTimeout(async () => {
      try {
        const r = await fetch('/api/geocode/suggest?q=' + encodeURIComponent(q), { credentials: 'same-origin' });
        const d = await r.json();
        setSugg(d.suggestions || []); setOpen((d.suggestions || []).length > 0);
      } catch (_) { setSugg([]); }
    }, 300);
  };
  return (
    <div style={{ position: 'relative' }}>
      <input className="input" value={value} placeholder="Начни вводить город…"
        onChange={e => { onChange(e.target.value); fetchSugg(e.target.value); }}
        onFocus={() => sugg.length && setOpen(true)}
        onBlur={() => setTimeout(() => setOpen(false), 150)} />
      {open && sugg.length > 0 && (
        <div className="card" style={{ position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 30, maxHeight: 220, overflowY: 'auto', background: 'var(--bg-raised)', marginTop: 4, padding: 4, boxShadow: '0 8px 24px rgba(0,0,0,0.18)' }}>
          {sugg.map((s, i) => (
            <div key={i} onMouseDown={() => { onPick(s); setOpen(false); setSugg([]); }}
              style={{ padding: '8px 10px', cursor: 'pointer', fontSize: 13, borderRadius: 6, color: 'var(--ink-secondary)' }}
              onMouseEnter={e => { e.currentTarget.style.background = 'var(--bg-base)'; }}
              onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; }}>
              {s.name}
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

// MatrixOctagram — декоративная октаграмма матрицы судьбы (8 точек + центр,
// старшие арканы Таро). Для превью в визарде, как NatalChart у натальной — ради
// гомогенности и имиджа. Числа иллюстративные (реальные считаются из даты).
const MatrixOctagram = ({ size = 260 }) => {
  const c = size / 2, R = size * 0.37, r = size * 0.072;
  const pts = [-90, -45, 0, 45, 90, 135, 180, 225].map(deg => {
    const a = deg * Math.PI / 180;
    return [c + R * Math.cos(a), c + R * Math.sin(a)];
  });
  const nums = [1, 21, 20, 10, 12, 3, 13, 14];
  const poly = (idx) => idx.map(i => pts[i].join(',')).join(' ');
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: 'block' }}>
      <g fill="none" stroke="var(--gold)" strokeWidth="1">
        <polygon points={poly([0, 2, 4, 6])} opacity="0.55" />
        <polygon points={poly([1, 3, 5, 7])} opacity="0.55" />
        {pts.map((p, i) => <line key={i} x1={c} y1={c} x2={p[0]} y2={p[1]} opacity="0.22" />)}
      </g>
      {pts.map((p, i) => (
        <g key={i}>
          <circle cx={p[0]} cy={p[1]} r={r} fill="var(--bg-base)" stroke="var(--gold)" strokeWidth="1.2" />
          <text x={p[0]} y={p[1]} textAnchor="middle" dominantBaseline="central" fontSize={r * 0.95} fill="var(--ink-secondary)" fontFamily="var(--font-display)">{nums[i]}</text>
        </g>
      ))}
      <circle cx={c} cy={c} r={r * 1.25} fill="var(--bg-base)" stroke="var(--gold)" strokeWidth="1.6" />
      <text x={c} y={c} textAnchor="middle" dominantBaseline="central" fontSize={r * 1.15} fill="var(--gold)" fontFamily="var(--font-display)" fontStyle="italic">2</text>
    </svg>
  );
};

const Wizard = () => {
  const [step, setStep] = React.useState(0);
  const [product, setProduct] = React.useState(() => {
    const q = new URLSearchParams(window.location.search).get('product');
    return ['natal', 'forecast', 'compat', 'matrix'].includes(q) ? q : 'natal';
  });
  const [personMode, setPersonMode] = React.useState('saved'); // saved | new
  const [selectedPerson, setSelectedPerson] = React.useState(null);
  const [secondPerson, setSecondPerson] = React.useState(null);
  const [tip, setTip] = React.useState(false); // аудио-комментарий пока не реализован
  const [payMethod, setPayMethod] = React.useState('sbp'); // СБП по умолчанию: 0.7% против 2.8% картой

  // Backend state
  const [persons, setPersons] = React.useState([]);
  const [user, setUser] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [submitting, setSubmitting] = React.useState(false);
  const [submitErr, setSubmitErr] = React.useState(null);

  // Контролируемая форма ввода персоны (step 1 mode=new, step 2; для совместимости — Партнёр 1).
  const [form, setForm] = React.useState({ name: '', dob: '', time: '', place: '', placeLat: 0, placeLng: 0, placeTz: '', gender: 'female', saveAsPerson: true });
  const setF = (k, v) => setForm(f => ({ ...f, [k]: v }));
  // Вторая форма — Партнёр 2 для совместимости (оба партнёра редактируемы на шаге «Данные»).
  const [form2, setForm2] = React.useState({ name: '', dob: '', time: '', place: '', placeLat: 0, placeLng: 0, placeTz: '', gender: 'male', saveAsPerson: true });
  const setF2 = (k, v) => setForm2(f => ({ ...f, [k]: v }));
  // Совместимость: подтверждение права предоставить данные второго человека (152-ФЗ — третье лицо).
  const [partner2Consent, setPartner2Consent] = React.useState(false);

  // Guest-checkout (не залогинен): email + согласие инлайн — фримиум без account-wall.
  const [guestEmail, setGuestEmail] = React.useState('');
  const [guestConsent, setGuestConsent] = React.useState(false);
  const [guestMarketing, setGuestMarketing] = React.useState(false);

  // Персона → объект формы (born_date "YYYY-MM-DD" → "DD.MM.YYYY"). Для новой/пустой
  // персоны saveAsPerson=true (сохраним при заказе), для существующей — false (не дублируем).
  const personToForm = (p, fallbackGender) => {
    if (!p) return { name: '', dob: '', time: '', place: '', placeLat: 0, placeLng: 0, placeTz: '', gender: fallbackGender || 'female', saveAsPerson: true };
    const iso = p.born_date || '';
    const dot = iso.length >= 10 ? `${iso.slice(8, 10)}.${iso.slice(5, 7)}.${iso.slice(0, 4)}` : '';
    return { name: p.name || '', dob: dot, time: p.born_time || '', place: p.place || '', placeLat: p.lat || 0, placeLng: p.lon || 0, placeTz: p.tz_name || '', gender: p.gender || fallbackGender || 'female', saveAsPerson: false };
  };

  React.useEffect(() => {
    (async () => {
      try {
        const [meR, psR] = await Promise.all([
          fetch('/api/auth/me', { credentials: 'same-origin' }),
          fetch('/api/persons', { credentials: 'same-origin' }),
        ]);
        if (meR.ok) {
          const me = await meR.json();
          setUser(me.user || me);
        }
        if (psR.ok) {
          const data = await psR.json();
          const list = data.persons || [];
          setPersons(list);
          // Если в URL передан ?person=<id> — выбираем именно его
          const qsPerson = new URLSearchParams(window.location.search).get('person');
          const preselected = qsPerson && list.find(p => p.id === qsPerson);
          const def = preselected || list.find(p => p.is_default) || list[0];
          if (def) setSelectedPerson(def.id);
          if (list.length > 1) setSecondPerson(list[1].id);
          // если нет ни одной персоны — переключаем на "новый"
          if (list.length === 0) setPersonMode('new');
        }
      } catch (e) {
        console.warn('wizard.load', e);
      } finally {
        setLoading(false);
      }
    })();
  }, []);

  // Цены/названия тянутся с бэка (window.__catalog) с фолбэками. Ключи визарда
  // (forecast/compat) маппятся на каталожные (year_ahead/compatibility).
  const PRODUCTS = {
    natal:    { name: catalogTitle('natal', 'Натальная карта'), price: catalogPrice('natal', 1990), desc: 'Глубокий разбор личности', accent: 'gold', planets: ['sun','moon','mercury'] },
    forecast: { name: catalogTitle('year_ahead', 'Прогноз на год'),  price: catalogPrice('year_ahead', 2990), desc: 'Транзиты и окна возможностей', accent: 'celest', planets: ['jupiter','saturn'] },
    compat:   { name: catalogTitle('compatibility', 'Совместимость'),    price: catalogPrice('compatibility', 2490), desc: 'Синастрия двух карт',       accent: 'rose', planets: ['venus','mars'] },
    matrix:   { name: catalogTitle('matrix', 'Матрица судьбы'),   price: catalogPrice('matrix', 1490), desc: 'Разбор по дате рождения',   accent: 'sage', planets: ['sun','moon','mercury'] },
  };

  const next = () => setStep(Math.min(WIZARD_STEPS.length - 1, step + 1));
  const prev = () => setStep(Math.max(0, step - 1));

  // Поля рождения — переиспользуются для обычной формы и для обоих партнёров совместимости.
  const renderBirthFields = (f, set, dateOnly = false) => (
    <div className="col gap-4">
      {!dateOnly && (
        <label className="field">
          <span className="label">Имя</span>
          <input className="input" value={f.name} onChange={e => set('name', e.target.value)} placeholder="Как зовут?" />
        </label>
      )}
      {dateOnly ? (
        <label className="field">
          <span className="label">Дата рождения</span>
          <input className="input mono" inputMode="numeric" maxLength={10} value={f.dob} onChange={e => set('dob', maskDate(e.target.value))} placeholder="ДД.ММ.ГГГГ" />
        </label>
      ) : (
        <div className="row gap-4 row-stack">
          <label className="field" style={{ flex: 1 }}>
            <span className="label">Дата</span>
            <input className="input mono" inputMode="numeric" maxLength={10} value={f.dob} onChange={e => set('dob', maskDate(e.target.value))} placeholder="ДД.ММ.ГГГГ" />
          </label>
          <label className="field" style={{ flex: 1 }}>
            <span className="label">Время</span>
            <input className="input mono" inputMode="numeric" maxLength={5} value={f.time} onChange={e => set('time', maskTime(e.target.value))} placeholder="чч:мм" />
          </label>
        </div>
      )}
      {!dateOnly && (
        <label className="field">
          <span className="label">Место рождения</span>
          <PlaceField value={f.place} onChange={v => set('place', v)} onPick={s => { set('place', s.name); set('placeLat', s.lat); set('placeLng', s.lng); set('placeTz', s.tz_name); }} />
        </label>
      )}
      <label className="field">
        <span className="label">Пол</span>
        <select className="input" value={f.gender} onChange={e => set('gender', e.target.value)}>
          <option value="female">Женский</option>
          <option value="male">Мужской</option>
        </select>
      </label>
      <label className="row gap-3" style={{ alignItems: 'flex-start', cursor: 'pointer' }}>
        <input type="checkbox" checked={f.saveAsPerson} onChange={e => set('saveAsPerson', e.target.checked)} style={{ marginTop: 4 }} />
        <span style={{ fontSize: '13px', color: 'var(--ink-secondary)' }}>Сохранить в моих персонах</span>
      </label>
    </div>
  );

  // Префилл форм при переходе на step-2.
  React.useEffect(() => {
    if (step !== 2) return;
    if (product === 'compat') {
      // Оба партнёра — из выбранных персон (если выбраны), но полностью редактируемы.
      setForm(personToForm(persons.find(x => x.id === selectedPerson), 'female'));
      setForm2(personToForm(persons.find(x => x.id === secondPerson), 'male'));
      return;
    }
    if (personMode === 'saved' && selectedPerson) {
      setForm(personToForm(persons.find(x => x.id === selectedPerson), 'female'));
    }
  }, [step, product, personMode, selectedPerson, secondPerson, persons]);

  // Отправка заказа на бэкенд + переход на оплату.
  // Для compatibility — обязательны две сохранённые персоны.
  // Для natal/year_ahead — берём поля из step-2 формы (даже если step-1 picker
  // выбрал сохранённую персону, эти поля пред-заполнены и user мог их править).
  const submitOrder = async () => {
    setSubmitting(true);
    setSubmitErr(null);
    try {
      const service = PRODUCT_TO_SERVICE[product];
      const body = { service };
      if (service === 'compatibility') {
        // Оба партнёра берутся из редактируемых форм шага «Данные» (inline),
        // поэтому любые правки пользователя попадают в заказ.
        const mkBirth = (f) => ({
          name: f.name.trim(),
          born_date: dotDateToISO(f.dob),
          born_time: f.time.trim(),
          tz_name: f.placeTz || '',
          place: f.place.trim(),
          lat: f.placeLat || 0,
          lng: f.placeLng || 0,
          gender: f.gender,
        });
        const b1 = mkBirth(form);
        const b2 = mkBirth(form2);
        if (!b1.name || !b1.born_date || !b1.place) throw new Error('Заполни данные первого человека: имя, дата и место рождения');
        if (!b2.name || !b2.born_date || !b2.place) throw new Error('Заполни данные второго человека: имя, дата и место рождения');
        if (!partner2Consent) throw new Error('Подтверди, что вправе предоставить данные второго человека');
        body.partner1 = b1;
        body.partner2 = b2;
        body.partner2_consent = true;
        // Best-effort: сохраняем каждого партнёра в персоны, если отмечено.
        const savePerson = async (f, b) => {
          if (!f.saveAsPerson) return;
          try {
            await fetch('/api/persons', {
              method: 'POST', credentials: 'same-origin',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ name: b.name, born_date: b.born_date, born_time: b.born_time, tz_name: b.tz_name || '', place: b.place, lat: b.lat || 0, lon: b.lng || 0, relation: '', gender: b.gender }),
            });
          } catch (_) { /* best-effort */ }
        };
        await savePerson(form, b1);
        await savePerson(form2, b2);
      } else {
        body.birth = {
          name: form.name.trim(),
          born_date: dotDateToISO(form.dob),
          born_time: form.time.trim(),
          tz_name: form.placeTz || '',
          place: form.place.trim(),
          lat: form.placeLat || 0,
          lng: form.placeLng || 0,
          gender: form.gender,
        };
        if (!body.birth.born_date) {
          throw new Error('Укажи дату рождения');
        }
        // Матрица судьбы — date-only: имя/место не обязательны.
        if (service !== 'matrix' && (!body.birth.name || !body.birth.place)) {
          throw new Error('Заполни имя, дату и место рождения');
        }
        // Прогноз на год требует период — по умолчанию ближайшие 12 месяцев.
        if (service === 'year_ahead') {
          const ymd = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
          const from = new Date();
          const to = new Date(from); to.setFullYear(to.getFullYear() + 1);
          body.from_date = ymd(from);
          body.to_date = ymd(to);
        }
        // Сохраняем введённые данные как переиспользуемую персону (если попросили).
        // Best-effort: ошибка сохранения не должна ломать оформление заказа.
        if (form.saveAsPerson) {
          try {
            await fetch('/api/persons', {
              method: 'POST',
              credentials: 'same-origin',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({
                name: body.birth.name,
                born_date: body.birth.born_date,
                born_time: body.birth.born_time,
                tz_name: body.birth.tz_name || '',
                place: body.birth.place,
                lat: body.birth.lat || 0,
                lon: body.birth.lng || 0,
                relation: '',
                gender: form.gender,
              }),
            });
          } catch (_) { /* best-effort */ }
        }
      }
      let endpoint = '/api/orders';
      if (!user) {
        // Гость: заказ без обязательной регистрации (создаст passwordless-аккаунт + сессию).
        const email = guestEmail.trim();
        if (!email || !email.includes('@')) throw new Error('Укажи email — на него придёт разбор');
        if (!guestConsent) throw new Error('Подтверди согласие с условиями, чтобы продолжить');
        body.email = email;
        body.consent_pdn = true;
        body.consent_cross_border = true;
        body.consent_marketing = guestMarketing;
        endpoint = '/api/checkout/guest';
      }
      const r = await fetch(endpoint, {
        method: 'POST',
        credentials: 'same-origin',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      });
      if (r.status === 401) { window.location.href = '/login?next=/order/new'; return; }
      if (r.status === 412) { window.location.href = '/consent'; return; }
      const data = await r.json();
      if (!r.ok) throw new Error(data.error || `HTTP ${r.status}`);
      // Запускаем mock-платёж
      const pr = await fetch('/api/payments/mock/create', {
        method: 'POST',
        credentials: 'same-origin',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ order_id: data.order_id, payment_method: payMethod }),
      });
      const pd = await pr.json();
      if (!pr.ok) throw new Error(pd.error || `HTTP ${pr.status}`);
      window.location.href = pd.payment_url || `/mock-checkout/${data.order_id}`;
    } catch (e) {
      console.error('order.submit', e);
      setSubmitErr(e.message || 'Не удалось создать заказ');
      setSubmitting(false);
    }
  };

  return (
    <div data-screen-label="09 Wizard" style={{ minHeight: 'calc(100vh - 120px)', position: 'relative', overflow: 'hidden' }}>
      {/* Background chart */}
      <div style={{ position: 'absolute', right: -240, top: -100, opacity: 0.5, pointerEvents: 'none' }}>
        <NatalChartBg size={900} opacity={0.45} />
      </div>

      <div className="wizard-shell" style={{ position: 'relative', maxWidth: '1100px', width: '100%', margin: '0 auto' }}>
        {/* Header */}
        <div className="between between-stack" style={{ marginBottom: '48px' }}>
          <button className="btn btn-ghost btn-sm" onClick={() => window.__nav?.('landing')}>
            <IconArrowLeft size={14} /> Назад
          </button>
          <div className="row gap-2" style={{ alignItems: 'center' }}>
            <span className="mono muted" style={{ fontSize: '11px' }}>Шаг {step + 1} / {WIZARD_STEPS.length}</span>
            <span style={{ width: 80, height: 2, background: 'var(--line)', borderRadius: 999, overflow: 'hidden', marginLeft: 8 }}>
              <span style={{
                display: 'block', height: '100%',
                width: `${((step + 1) / WIZARD_STEPS.length) * 100}%`,
                background: 'var(--gold)',
                transition: 'width 320ms ease',
              }} />
            </span>
          </div>
        </div>

        {/* Stepper */}
        <div className="row" style={{ gap: '12px', marginBottom: '48px', flexWrap: 'wrap' }}>
          {WIZARD_STEPS.map((s, i) => {
            const canGo = i < step; // на пройденные шаги можно вернуться и поправить
            return (
            <div key={s.id} onClick={() => { if (canGo) { setSubmitErr(null); setStep(i); } }}
              className="row gap-3"
              title={canGo ? 'Вернуться к шагу' : undefined}
              style={{ alignItems: 'center', opacity: i > step ? 0.4 : 1, cursor: canGo ? 'pointer' : 'default' }}>
              <div style={{
                width: 28, height: 28, borderRadius: '50%',
                border: '1px solid var(--line)',
                background: i < step ? 'var(--gold)' : i === step ? 'transparent' : 'transparent',
                color: i < step ? 'var(--bg-base)' : i === step ? 'var(--gold)' : 'var(--ink-muted)',
                borderColor: i <= step ? 'var(--gold)' : 'var(--line)',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontFamily: 'var(--font-mono)', fontSize: '11px',
              }}>
                {i < step ? <IconCheck size={12} /> : i + 1}
              </div>
              <span className="mono" style={{ fontSize: '11px', letterSpacing: '0.12em', textTransform: 'uppercase', color: i === step ? 'var(--ink-primary)' : 'var(--ink-muted)' }}>
                {s.label}
              </span>
              {i < WIZARD_STEPS.length - 1 && <span style={{ width: 24, height: 1, background: 'var(--line)' }} />}
            </div>
            );
          })}
        </div>

        {/* Step content */}
        <div className="fade-in" key={step}>
          {step === 0 && (
            <>
              <h1 className="display-lg" style={{ marginBottom: '16px' }}>
                Какой <span className="italic gold">разбор</span> сейчас?
              </h1>
              <p style={{ color: 'var(--ink-secondary)', fontSize: '17px', marginBottom: '40px', maxWidth: '520px' }}>
                Выбери, что важно прямо сейчас. Каждый разбор основан на твоей натальной карте.
              </p>
              <div className="rgrid" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '20px' }}>
                {Object.entries(PRODUCTS).map(([id, p]) => (
                  <button key={id} onClick={() => setProduct(id)} style={{
                    textAlign: 'left',
                    background: product === id ? 'var(--bg-elevated)' : 'var(--bg-raised)',
                    border: product === id ? `1.5px solid var(--${p.accent})` : '1px solid var(--line)',
                    borderRadius: '18px',
                    padding: '28px',
                    cursor: 'pointer',
                    transition: 'all 200ms',
                    position: 'relative',
                  }}>
                    <div className="between" style={{ marginBottom: '20px' }}>
                      <div className="row gap-2">
                        {p.planets.map((pl, j) => (
                          <div key={j} style={{ width: 32, height: 32, borderRadius: '50%', border: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: `var(--${p.accent})` }}>
                            <PlanetGlyph kind={pl} size={16} />
                          </div>
                        ))}
                      </div>
                      {product === id && (
                        <div style={{ width: 24, height: 24, borderRadius: '50%', background: `var(--${p.accent})`, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--bg-base)' }}>
                          <IconCheck size={14} />
                        </div>
                      )}
                    </div>
                    <h3 className="display-md" style={{ fontSize: '28px', marginBottom: '8px' }}>{p.name}</h3>
                    <p style={{ fontSize: '13.5px', color: 'var(--ink-secondary)', marginBottom: '24px', lineHeight: 1.5 }}>{p.desc}</p>
                    <div className="between">
                      <span className="mono muted" style={{ fontSize: '11px' }}>PDF · {id === 'forecast' ? '38' : id === 'compat' ? '42' : id === 'matrix' ? '30' : '50'} стр.</span>
                      <span className="display-md" style={{ fontSize: '24px', color: `var(--${p.accent})` }}>{p.price} ₽</span>
                    </div>
                  </button>
                ))}
              </div>
            </>
          )}

          {step === 1 && (
            <>
              <h1 className="display-lg" style={{ marginBottom: '16px' }}>
                Для <span className="italic gold">кого</span> разбор?
              </h1>
              <p style={{ color: 'var(--ink-secondary)', fontSize: '17px', marginBottom: '32px', maxWidth: '520px' }}>
                {product === 'compat' ? 'Выбери двух из сохранённых — или оставь как есть и заполни данные вручную. Данные обоих можно отредактировать на следующем шаге.' : 'Выбери из сохранённых или добавь нового человека.'}
              </p>

              {/* Mode toggle (для совместимости скрыт — оба партнёра редактируются на шаге «Данные») */}
              {product !== 'compat' && (
              <div className="row gap-2" style={{ marginBottom: '32px', padding: '4px', border: '1px solid var(--line)', borderRadius: '12px', background: 'var(--bg-raised)', width: 'fit-content' }}>
                {[
                  { id: 'saved', label: 'Сохранённые персоны' },
                  { id: 'new',   label: 'Новый человек' },
                ].map(m => (
                  <button key={m.id} onClick={() => setPersonMode(m.id)} style={{
                    padding: '10px 16px',
                    borderRadius: '8px',
                    border: 'none',
                    background: personMode === m.id ? 'var(--ink-primary)' : 'transparent',
                    color: personMode === m.id ? 'var(--bg-base)' : 'var(--ink-secondary)',
                    cursor: 'pointer',
                    fontSize: '13px',
                    fontFamily: 'var(--font-ui)',
                  }}>{m.label}</button>
                ))}
              </div>
              )}

              {(personMode === 'saved' || product === 'compat') && (
                <>
                  {product === 'compat' && (
                    <div className="card" style={{ padding: '32px', marginBottom: '24px', background: 'var(--bg-raised)' }}>
                      <div className="row gap-6 row-stack" style={{ alignItems: 'center' }}>
                        <div style={{ flex: 1 }}>
                          <div className="label" style={{ marginBottom: '8px' }}>Партнёр 1</div>
                          <select className="select" value={selectedPerson || ''} onChange={e => setSelectedPerson(e.target.value)}>
                            {persons.map(p => <option key={p.id} value={p.id}>{p.name}{p.relation ? ` · ${p.relation}` : ''}</option>)}
                          </select>
                        </div>
                        <div className="rose" style={{ paddingTop: 20 }}><IconHeart size={28} /></div>
                        <div style={{ flex: 1 }}>
                          <div className="label" style={{ marginBottom: '8px' }}>Партнёр 2</div>
                          <select className="select" value={secondPerson || ''} onChange={e => setSecondPerson(e.target.value)}>
                            {persons.map(p => <option key={p.id} value={p.id}>{p.name}{p.relation ? ` · ${p.relation}` : ''}</option>)}
                          </select>
                        </div>
                      </div>
                    </div>
                  )}
                  <div className="rgrid-2" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '14px' }}>
                    {persons.length === 0 && !loading && (
                      <div className="muted" style={{ gridColumn: '1 / -1', padding: '20px', fontSize: '14px' }}>
                        У тебя пока нет сохранённых персон — добавь нового человека ниже.
                      </div>
                    )}
                    {persons.map(p => {
                      const selected = product === 'compat'
                        ? (p.id === selectedPerson || p.id === secondPerson)
                        : p.id === selectedPerson;
                      const isoDate = p.born_date || '';
                      const showDate = isoDate.length >= 10 ? `${isoDate.slice(8,10)}.${isoDate.slice(5,7)}.${isoDate.slice(0,4)}` : '—';
                      return (
                        <button key={p.id} onClick={() => product !== 'compat' && setSelectedPerson(p.id)} style={{
                          textAlign: 'left',
                          background: selected ? 'var(--bg-elevated)' : 'var(--bg-raised)',
                          border: selected ? '1.5px solid var(--gold)' : '1px solid var(--line)',
                          borderRadius: '14px',
                          padding: '20px',
                          cursor: 'pointer',
                          transition: 'all 200ms',
                        }}>
                          <div className="row gap-3" style={{ alignItems: 'center', marginBottom: '12px' }}>
                            <div style={{ width: 40, height: 40, borderRadius: '50%', border: '1px solid var(--gold)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--gold)' }}>
                              <IconUser size={18} />
                            </div>
                            <div>
                              <div style={{ fontSize: '15px' }}>{p.name}</div>
                              {p.relation && <div className="mono muted" style={{ fontSize: '10px' }}>{p.relation}</div>}
                            </div>
                          </div>
                          <div className="mono muted" style={{ fontSize: '11px' }}>{showDate}{p.place ? ` · ${p.place}` : ''}</div>
                        </button>
                      );
                    })}
                    {product !== 'compat' && (
                    <button onClick={() => setPersonMode('new')} style={{
                      border: '1.5px dashed var(--line)',
                      borderRadius: '14px',
                      background: 'transparent',
                      padding: '20px',
                      cursor: 'pointer',
                      color: 'var(--ink-muted)',
                      display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px',
                      fontFamily: 'var(--font-display)', fontStyle: 'italic', fontSize: '17px',
                    }}>
                      <IconPlus size={16} /> Новый
                    </button>
                    )}
                  </div>
                </>
              )}

              {personMode === 'new' && product !== 'compat' && (
                <div className="card" style={{ padding: '32px', background: 'var(--bg-raised)' }}>
                  <div className="col gap-4">
                    <label className="field">
                      <span className="label">Имя</span>
                      <input className="input" placeholder="Как зовут?" value={form.name} onChange={e => setF('name', e.target.value)} />
                    </label>
                    <div className="row gap-4">
                      <label className="field" style={{ flex: 1 }}>
                        <span className="label">Дата рождения</span>
                        <input className="input mono" placeholder="ДД.ММ.ГГГГ" inputMode="numeric" maxLength={10} value={form.dob} onChange={e => setF('dob', maskDate(e.target.value))} />
                      </label>
                      <label className="field" style={{ flex: 1 }}>
                        <span className="label">Время — если знаешь</span>
                        <input className="input mono" placeholder="чч:мм" inputMode="numeric" maxLength={5} value={form.time} onChange={e => setF('time', maskTime(e.target.value))} />
                      </label>
                    </div>
                    <label className="field">
                      <span className="label">Место рождения</span>
                      <input className="input" placeholder="Город, страна" value={form.place} onChange={e => setF('place', e.target.value)} />
                    </label>
                    <label className="field">
                      <span className="label">Пол</span>
                      <select className="input" value={form.gender} onChange={e => setF('gender', e.target.value)}>
                        <option value="female">Женский</option>
                        <option value="male">Мужской</option>
                      </select>
                      <span className="mono muted" style={{ fontSize: '11px', marginTop: '4px' }}>Чтобы разбор был в правильном роде: «ты родилась» / «ты родился».</span>
                    </label>
                    <label className="row gap-3" style={{ alignItems: 'flex-start', marginTop: '12px', cursor: 'pointer' }}>
                      <input type="checkbox" checked={form.saveAsPerson} onChange={e => setF('saveAsPerson', e.target.checked)} style={{ marginTop: 4 }} />
                      <span style={{ fontSize: '13px', color: 'var(--ink-secondary)' }}>Сохранить в моих персонах — чтобы заказывать повторно</span>
                    </label>
                  </div>
                </div>
              )}
            </>
          )}

          {step === 2 && (
            <>
              <h1 className="display-lg" style={{ marginBottom: '16px' }}>
                Уточни <span className="italic gold">данные</span>
              </h1>
              <p style={{ color: 'var(--ink-secondary)', fontSize: '17px', marginBottom: '32px', maxWidth: '520px' }}>
                Чем точнее данные — тем глубже разбор. Особенно важно время рождения для домов карты.
              </p>

              {product === 'compat' ? (
              <>
              <div className="rgrid" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '24px' }}>
                <div className="card" style={{ padding: '28px', background: 'var(--bg-raised)' }}>
                  <div className="label" style={{ marginBottom: '16px', color: 'var(--rose)' }}>Партнёр 1</div>
                  {renderBirthFields(form, setF)}
                </div>
                <div className="card" style={{ padding: '28px', background: 'var(--bg-raised)' }}>
                  <div className="label" style={{ marginBottom: '16px', color: 'var(--rose)' }}>Партнёр 2</div>
                  {renderBirthFields(form2, setF2)}
                </div>
              </div>
              <label className="row gap-3" style={{ alignItems: 'flex-start', marginTop: '20px', cursor: 'pointer' }}>
                <input type="checkbox" checked={partner2Consent} onChange={e => setPartner2Consent(e.target.checked)} style={{ marginTop: 4 }} />
                <span style={{ fontSize: '13px', color: 'var(--ink-secondary)' }}>
                  Подтверждаю, что вправе предоставить данные второго человека и уведомил(а) его об этом разборе. <span className="gold">Обязательно</span>
                </span>
              </label>
              </>
              ) : product === 'matrix' ? (
              <div className="rgrid" style={{ display: 'grid', gridTemplateColumns: '1.1fr 1fr', gap: '32px' }}>
                <div className="card" style={{ padding: '32px', background: 'var(--bg-raised)' }}>
                  <div className="col gap-4">
                    <label className="field">
                      <span className="label">Дата рождения</span>
                      <input className="input mono" inputMode="numeric" maxLength={10} value={form.dob} onChange={e => setF('dob', maskDate(e.target.value))} placeholder="ДД.ММ.ГГГГ" />
                    </label>
                    <label className="field">
                      <span className="label">Пол</span>
                      <select className="input" value={form.gender} onChange={e => setF('gender', e.target.value)}>
                        <option value="female">Женский</option>
                        <option value="male">Мужской</option>
                      </select>
                      <span className="mono muted" style={{ fontSize: '11px', marginTop: '4px' }}>Чтобы разбор был в правильном роде.</span>
                    </label>
                    <div className="card" style={{ background: 'var(--bg-base)', padding: '16px', borderColor: 'var(--gold-dim)' }}>
                      <div className="mono muted" style={{ fontSize: '11px', lineHeight: 1.5 }}>
                        Матрица судьбы считается по 22 арканам Таро только из <b>даты рождения</b>. Время и место не нужны.
                      </div>
                    </div>
                  </div>
                </div>

                {/* Превью октаграммы — гомогенно с натальной картой */}
                <div className="card" style={{ padding: '24px', background: 'var(--bg-raised)', position: 'relative', overflow: 'hidden' }}>
                  <div className="label" style={{ marginBottom: '20px' }}>Превью матрицы</div>
                  <div style={{ display: 'flex', justifyContent: 'center', marginBottom: '20px' }}>
                    <MatrixOctagram size={260} />
                  </div>
                  <div className="col gap-2">
                    <div className="between" style={{ fontSize: '13px' }}>
                      <span className="muted">Главный аркан</span>
                      <span className="row gap-2" style={{ alignItems: 'center' }}>Верховная Жрица</span>
                    </div>
                    <div className="between" style={{ fontSize: '13px' }}>
                      <span className="muted">Точки судьбы</span>
                      <span>8 + центр</span>
                    </div>
                    <div className="between" style={{ fontSize: '13px' }}>
                      <span className="muted">Система</span>
                      <span>22 аркана Таро</span>
                    </div>
                  </div>
                </div>
              </div>
              ) : (
              <div className="rgrid" style={{ display: 'grid', gridTemplateColumns: '1.3fr 1fr', gap: '32px' }}>
                <div className="card" style={{ padding: '32px', background: 'var(--bg-raised)' }}>
                  <div className="col gap-4">
                    <label className="field">
                      <span className="label">Имя</span>
                      <input className="input" value={form.name} onChange={e => setF('name', e.target.value)} placeholder="Как зовут?" />
                    </label>
                    <div className="row gap-4 row-stack">
                      <label className="field" style={{ flex: 1 }}>
                        <span className="label">Дата</span>
                        <input className="input mono" inputMode="numeric" maxLength={10} value={form.dob} onChange={e => setF('dob', maskDate(e.target.value))} placeholder="ДД.ММ.ГГГГ" />
                      </label>
                      <label className="field" style={{ flex: 1 }}>
                        <span className="label">Время</span>
                        <input className="input mono" inputMode="numeric" maxLength={5} value={form.time} onChange={e => setF('time', maskTime(e.target.value))} placeholder="чч:мм" />
                      </label>
                    </div>
                    <label className="field">
                      <span className="label">Место рождения</span>
                      <PlaceField value={form.place} onChange={v => setF('place', v)} onPick={s => { setF('place', s.name); setF('placeLat', s.lat); setF('placeLng', s.lng); setF('placeTz', s.tz_name); }} />
                    </label>
                    <label className="field">
                      <span className="label">Пол</span>
                      <select className="input" value={form.gender} onChange={e => setF('gender', e.target.value)}>
                        <option value="female">Женский</option>
                        <option value="male">Мужской</option>
                      </select>
                      <span className="mono muted" style={{ fontSize: '11px', marginTop: '4px' }}>Чтобы разбор был в правильном роде: «ты родилась» / «ты родился».</span>
                    </label>
                    {product === 'forecast' && (() => {
                      const ymd = (d) => `${String(d.getDate()).padStart(2, '0')}.${String(d.getMonth() + 1).padStart(2, '0')}.${d.getFullYear()}`;
                      const from = new Date();
                      const to = new Date(from); to.setFullYear(to.getFullYear() + 1);
                      return (
                        <div className="card" style={{ background: 'var(--bg-base)', padding: '16px', borderColor: 'var(--celest)' }}>
                          <div className="label" style={{ marginBottom: '4px' }}>Период прогноза</div>
                          <div style={{ fontSize: '14px' }}>Ближайшие 12 месяцев · {ymd(from)} — {ymd(to)}</div>
                        </div>
                      );
                    })()}
                    <div className="card" style={{ background: 'var(--bg-base)', padding: '16px', borderColor: 'var(--gold-dim)' }}>
                      <div className="row gap-3" style={{ alignItems: 'flex-start' }}>
                        <IconShield size={16} style={{ color: 'var(--gold)', marginTop: 2 }} />
                        <div>
                          <div style={{ fontSize: '13px', marginBottom: '4px' }}>Что мы рассчитаем с этими данными</div>
                          <div className="mono muted" style={{ fontSize: '11px', lineHeight: 1.5 }}>
                            Положения 10 планет, 12 домов, 28+ аспектов, лунные узлы, Хирон, Лилит — через Swiss Ephemeris.
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>

                {/* Live preview */}
                <div className="card" style={{ padding: '24px', background: 'var(--bg-raised)', position: 'relative', overflow: 'hidden' }}>
                  <div className="label" style={{ marginBottom: '20px' }}>Превью карты</div>
                  <div style={{ display: 'flex', justifyContent: 'center', marginBottom: '20px' }}>
                    <NatalChart size={260} animated={true} />
                  </div>
                  <div className="col gap-2">
                    <div className="between" style={{ fontSize: '13px' }}>
                      <span className="muted">Солнце</span>
                      <span className="row gap-2" style={{ alignItems: 'center' }}>
                        <ZodiacGlyph kind="cancer" size={14} /> Рак <span className="mono muted">21°</span>
                      </span>
                    </div>
                    <div className="between" style={{ fontSize: '13px' }}>
                      <span className="muted">Луна</span>
                      <span className="row gap-2" style={{ alignItems: 'center' }}>
                        <ZodiacGlyph kind="scorpio" size={14} /> Скорпион <span className="mono muted">8°</span>
                      </span>
                    </div>
                    <div className="between" style={{ fontSize: '13px' }}>
                      <span className="muted">Асцендент</span>
                      <span className="row gap-2" style={{ alignItems: 'center' }}>
                        <ZodiacGlyph kind="virgo" size={14} /> Дева <span className="mono muted">2°</span>
                      </span>
                    </div>
                  </div>
                </div>
              </div>
              )}
            </>
          )}

          {step === 3 && (
            <>
              <h1 className="display-lg" style={{ marginBottom: '32px' }}>
                <span className="italic gold">Оплата</span>
              </h1>

              <div className="rgrid" style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: '32px', alignItems: 'flex-start' }}>
                <div className="card" style={{ padding: '32px', background: 'var(--bg-raised)' }}>
                  <div className="label" style={{ marginBottom: '20px' }}>Способ оплаты</div>
                  <div className="col gap-3">
                    {[
                      { id: 'sbp', label: 'СБП', sub: 'Перевод по QR · быстро и без комиссии', recommended: true },
                      { id: 'card', label: 'Банковская карта', sub: 'Visa, MC, МИР · через ЮKassa' },
                      { id: 'wallet', label: 'ЮMoney / SberPay', sub: 'кошельки' },
                    ].map((m) => {
                      const active = payMethod === m.id;
                      return (
                      <label key={m.id} className="card" style={{
                        cursor: 'pointer',
                        padding: '16px 20px',
                        background: active ? 'var(--bg-elevated)' : 'var(--bg-base)',
                        borderColor: active ? 'var(--gold)' : 'var(--line)',
                        display: 'flex', alignItems: 'center', gap: '14px',
                      }}>
                        <input type="radio" name="pay" checked={active} onChange={() => setPayMethod(m.id)} />
                        <div style={{ flex: 1 }}>
                          <div style={{ fontSize: '14px', display: 'flex', alignItems: 'center', gap: '8px' }}>
                            {m.label}
                            {m.recommended && <span className="mono" style={{ fontSize: '10px', color: 'var(--gold)', border: '1px solid var(--gold)', borderRadius: '4px', padding: '1px 6px' }}>рекомендуем</span>}
                          </div>
                          <div className="mono muted" style={{ fontSize: '11px' }}>{m.sub}</div>
                        </div>
                        {active && <IconLock size={14} style={{ color: 'var(--gold)' }} />}
                      </label>
                      );
                    })}
                  </div>

                  <div className="col gap-4" style={{ marginTop: '24px' }}>
                    <label className="field">
                      <span className="label">Email для PDF</span>
                      <input className="input" value={user?.email || ''} readOnly style={{ opacity: 0.75 }} />
                    </label>
                    <div className="mono muted" style={{ fontSize: '11px' }}>
                      PDF придёт на email, с которого ты вошла. Изменить — в кабинете.
                    </div>
                  </div>
                </div>

                {/* Summary */}
                <div className="card" style={{ padding: '28px', background: 'var(--bg-raised)', position: 'sticky', top: 100 }}>
                  <div className="label" style={{ marginBottom: '20px' }}>Заказ</div>
                  <div className="col gap-3" style={{ marginBottom: '20px' }}>
                    <div className="between">
                      <span style={{ fontSize: '14px' }}>{PRODUCTS[product].name}</span>
                      <span className="mono">{PRODUCTS[product].price} ₽</span>
                    </div>
                    <div className="between muted" style={{ fontSize: '13px' }}>
                      <span>Для: {product === 'compat'
                        ? `${persons.find(p => p.id === selectedPerson)?.name || '—'} × ${persons.find(p => p.id === secondPerson)?.name || '—'}`
                        : (personMode === 'saved' && selectedPerson ? (persons.find(p => p.id === selectedPerson)?.name || 'персона') : (form.name || 'новая персона'))}</span>
                    </div>
                    {tip && (
                      <div className="between" style={{ paddingTop: '12px', borderTop: '1px solid var(--line-soft)' }}>
                        <span style={{ fontSize: '13px' }}>Аудио-комментарий астролога</span>
                        <button onClick={() => setTip(false)} className="mono" style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--ink-muted)', fontSize: '11px' }}>+ 990 ₽</button>
                      </div>
                    )}
                  </div>
                  <div className="divider" style={{ marginBottom: '16px' }} />
                  <div className="between" style={{ marginBottom: '24px' }}>
                    <span className="mono muted" style={{ fontSize: '12px' }}>К оплате</span>
                    <span className="display-md" style={{ fontSize: '32px' }}>
                      {PRODUCTS[product].price + (tip ? 990 : 0)} ₽
                    </span>
                  </div>
                  {!user && (
                    <div className="col gap-3" style={{ marginBottom: '16px' }}>
                      <label className="col gap-1">
                        <span className="mono muted" style={{ fontSize: '12px' }}>Email — на него придёт PDF-разбор</span>
                        <input type="email" value={guestEmail} onChange={e => setGuestEmail(e.target.value)} placeholder="you@example.com"
                          style={{ padding: '12px 14px', borderRadius: '8px', border: '1px solid var(--line-soft)', background: 'transparent', color: 'inherit', fontSize: '15px' }} />
                      </label>
                      <label className="row gap-2" style={{ alignItems: 'flex-start', fontSize: '12px', color: 'var(--ink-muted)', cursor: 'pointer' }}>
                        <input type="checkbox" checked={guestConsent} onChange={e => setGuestConsent(e.target.checked)} style={{ marginTop: '3px' }} />
                        <span>Мне есть 18 лет, данные верны. Согласен с <a href="/terms" target="_blank">офертой</a>, <a href="/privacy" target="_blank">политикой обработки персональных данных</a> и тарифами, и на обработку данных рождения (в т.ч. передачу ИИ-сервису для генерации разбора).</span>
                      </label>
                      <label className="row gap-2" style={{ alignItems: 'flex-start', fontSize: '12px', color: 'var(--ink-muted)', cursor: 'pointer' }}>
                        <input type="checkbox" checked={guestMarketing} onChange={e => setGuestMarketing(e.target.checked)} style={{ marginTop: '3px' }} />
                        <span>Хочу получать полезные материалы и предложения на email (необязательно).</span>
                      </label>
                    </div>
                  )}
                  <button
                    className="btn btn-gold full"
                    style={{ width: '100%', justifyContent: 'center', padding: '14px', opacity: submitting ? 0.6 : 1 }}
                    disabled={submitting}
                    onClick={submitOrder}
                  >
                    <IconLock size={14} /> {submitting ? 'Создаём заказ…' : 'Оплатить'}
                  </button>
                  {submitErr && (
                    <div style={{ marginTop: '12px', padding: '10px 14px', background: 'color-mix(in oklab, var(--rose) 12%, transparent)', border: '1px solid var(--rose)', borderRadius: '8px', fontSize: '13px', color: 'var(--rose)' }}>
                      {submitErr}
                    </div>
                  )}
                  <div className="row gap-3" style={{ alignItems: 'center', justifyContent: 'center', marginTop: '16px' }}>
                    <IconShield size={12} style={{ color: 'var(--ink-muted)' }} />
                    <span className="mono muted" style={{ fontSize: '11px' }}>152-ФЗ · возврат 7 дней</span>
                  </div>
                </div>
              </div>
            </>
          )}
        </div>

        {/* Navigation */}
        {step < 3 && (
          <div className="between" style={{ marginTop: '48px', paddingTop: '24px', borderTop: '1px solid var(--line)' }}>
            <button className="btn btn-ghost" onClick={prev} disabled={step === 0} style={{ opacity: step === 0 ? 0.4 : 1 }}>
              <IconArrowLeft size={14} /> Назад
            </button>
            <button className="btn btn-gold" onClick={next}>
              {step === 2 ? 'К оплате' : 'Дальше'} <IconArrowRight size={14} />
            </button>
          </div>
        )}
      </div>
    </div>
  );
};

Object.assign(window, { Wizard });
