// free-calc.jsx — бесплатные расчёты: вход во freemium-воронку.
//
// Две карточки: натальная карта (дата, время, место) и матрица судьбы (одна
// дата). Обе живут здесь, а не внутри своих страниц: один и тот же расчёт
// стоит и на главной, и на посадочной странице продукта, а своя копия
// разошлась бы с продуктом при первой правке.
//
// Расчёт идёт по настоящим эфемеридам на бэкенде (/api/free/chart), а не по
// таблице знаков в браузере: у бесплатного расчёта и у платного разбора должны
// совпадать не только цифры, но и источник цифр.
//
// Переиспользует CardStars / rubFmt / catalogPrice из landing.jsx и PlaceField
// из ui-select.jsx — общая babel-область, порядок загрузки в spa.html.

const fcMaskTime = (s) => {
  const d = (s || '').replace(/\D/g, '').slice(0, 4);
  return d.length <= 2 ? d : d.slice(0, 2) + ':' + d.slice(2);
};

const fcInputStyle = {
  padding: '14px 16px', borderRadius: '10px', border: '1px solid var(--line)',
  background: 'rgba(255,255,255,0.03)', color: 'var(--ink-primary)', fontSize: '17px',
  textAlign: 'center', letterSpacing: '0.04em', width: '100%',
};

// FreeChartCard — бесплатный расчёт натальной карты.
//
// У матрицы хватало одной даты, здесь их три поля, и это не придирка к форме:
// без времени и места нет ни Асцендента, ни домов, а Луна за сутки уходит на
// тринадцать градусов и может оказаться в соседнем знаке. Поэтому время и
// место — не «дополнительно», а то, ради чего расчёт вообще персональный;
// без них честно показываем только Солнце и Луну и говорим об этом прямо.
const FreeChartCard = () => {
  // calcKind — что именно человек считает. Уточнение шага в воронке: без него
  // «запустил расчёт» не отличает натальную карту от матрицы, а это разные
  // страницы и разные причины ухода.
  const calcKind = 'chart';
  const [dob, setDob] = React.useState('');
  const [time, setTime] = React.useState('');
  const [place, setPlace] = React.useState('');
  const [picked, setPicked] = React.useState(null);
  const [result, setResult] = React.useState(null);
  const [calculating, setCalculating] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const [email, setEmail] = React.useState('');
  const [leadConsent, setLeadConsent] = React.useState(false);
  const [leadSent, setLeadSent] = React.useState(false);

  const isoDob = () => {
    const m = (dob || '').match(/^(\d{1,2})[.\-/](\d{1,2})[.\-/](\d{4})$/);
    return m ? `${m[3]}-${m[2].padStart(2, '0')}-${m[1].padStart(2, '0')}` : '';
  };

  const calc = async () => {
    const iso = isoDob();
    if (!iso) {
      // Отказ на валидации — тоже отсев, и его причина отличается от «расчёт
      // упал»: чинится он текстом подсказки, а не кодом.
      window.astro?.track?.('calc_failed', 'validation:date');
      setErr('Введи дату в формате ДД.ММ.ГГГГ'); return;
    }
    setErr(null); setCalculating(true);
    window.astro?.track?.('calc_started', calcKind);
    try {
      const r = await fetch('/api/free/chart', {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          born_date: iso,
          born_time: time,
          place,
          // Выбранный из списка город идёт координатами: одноимённые города
          // различает только выбор, и «Ростов» иначе уезжает не в тот Ростов.
          // Пояс идёт вместе с ними: без него бэкенд читал время рождения как
          // UTC, и Асцендент расходился с платным расчётом на весь сдвиг пояса.
          ...(picked ? { lat: picked.lat, lng: picked.lng, tz: picked.tz_name || '' } : {}),
        }),
      });
      const d = await r.json();
      if (!r.ok) throw new Error(d.error || 'Не удалось рассчитать');
      setResult(d);
      window.astro?.track?.('calc_done', calcKind);
    } catch (e) {
      window.astro?.track?.('calc_failed', (e && e.message) || 'unknown');
      setErr(e.message || 'Ошибка');
    } finally { setCalculating(false); }
  };

  const sendLead = async () => {
    if (!email.includes('@')) { setErr('Укажи корректный email'); return; }
    if (!leadConsent) { setErr('Подтверди согласие с условиями'); return; }
    setErr(null);
    try {
      await fetch('/api/free/lead', {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          email: email.trim(), kind: 'chart',
          born_date: isoDob(), born_time: time, place,
        }),
      });
    } catch (_) { /* best-effort: лид важен нам, а не человеку */ }
    window.astro?.track?.('email_given', calcKind);
    setLeadSent(true);
  };

  const goOrder = () => { window.location.href = '/order/new?product=natal'; };

  // Что показываем в результате. Асцендент появляется только когда есть и
  // время, и место: без них он не «примерный», а никакой.
  const placements = result ? [
    { label: 'Солнце', glyph: '☉', v: result.sun },
    { label: 'Луна', glyph: '☽', v: result.moon },
    { label: 'Асцендент', glyph: '↑', v: result.ascendant },
  ].filter(p => p.v) : [];

  return (
    <div className="card-glass" style={{ padding: '28px', borderRadius: '18px', width: '100%', maxWidth: '420px', position: 'relative', isolation: 'isolate' }}>
      <CardStars seed="chart-calc" behind />
      {!result ? (
        <div className="col gap-4">
          <div className="label">Бесплатный расчёт карты</div>
          <input value={dob} onChange={e => setDob(mxMaskDate(e.target.value))}
            placeholder="ДД.ММ.ГГГГ" inputMode="numeric" style={fcInputStyle} />
          <input value={time} onChange={e => setTime(fcMaskTime(e.target.value))}
            placeholder="ЧЧ:ММ — время рождения" inputMode="numeric" style={{ ...fcInputStyle, fontSize: '15px' }} />
          <div style={{ textAlign: 'left' }}>
            <PlaceField value={place} onChange={setPlace} onPick={(s) => { setPlace(s.name); setPicked(s); }} />
          </div>
          <button className="btn btn-primary" style={{ width: '100%', justifyContent: 'center', opacity: calculating ? 0.6 : 1 }}
            disabled={calculating} onClick={calc}>
            {calculating ? 'Считаем…' : 'Рассчитать бесплатно'}
            {!calculating && <IconArrowRight size={16} />}
          </button>
          {err && <div className="mono" style={{ fontSize: '12px', color: 'var(--rose)' }}>{err}</div>}
          <div className="mono muted" style={{ fontSize: '11px', textAlign: 'center', lineHeight: 1.6 }}>
            Без регистрации · результат сразу на экране<br />
            Не знаешь время — оставь пустым: посчитаем Солнце и Луну
          </div>
        </div>
      ) : (
        <div className="col gap-4">
          <div className="col" style={{ gap: '6px', textAlign: 'center' }}>
            <div className="label">Твоя карта</div>
            <div className="display-xl gold" style={{ fontSize: '44px', lineHeight: 1.1 }}>
              {result.sun ? result.sun.sign : '—'}
            </div>
            <div className="mono muted" style={{ fontSize: '11px' }}>Солнце · знак</div>
          </div>
          <div className="row" style={{ gap: '8px', flexWrap: 'wrap', justifyContent: 'center' }}>
            {placements.map(p => (
              <div key={p.label} style={{ minWidth: '104px', textAlign: 'center', padding: '10px 8px', border: '1px solid var(--line-soft)', borderRadius: '10px' }}>
                <div style={{ fontFamily: 'var(--font-display)', fontSize: '18px', color: 'var(--gold)' }}>{p.glyph} {p.v.sign}</div>
                <div className="mono muted" style={{ fontSize: '10px' }}>{p.label}</div>
              </div>
            ))}
          </div>
          {!result.ascendant && (
            // Не прячем недостающее: человек должен понимать, почему у него
            // две строки, а у подруги три, и что это чинится его же данными.
            <div className="mono muted" style={{ fontSize: '10.5px', lineHeight: 1.6, textAlign: 'center' }}>
              Асцендент считается от минуты и места рождения — укажи их, и он появится.
            </div>
          )}
          <p className="muted" style={{ fontSize: '14px', lineHeight: 1.5, textAlign: 'center' }}>{result.teaser}</p>
          <div className="col gap-3" style={{ borderTop: '1px solid var(--line-soft)', paddingTop: '20px' }}>
            {!leadSent && (
              <>
                <p style={{ fontSize: '14px', textAlign: 'center' }}>Прислать разбор этой карты на почту — что означают эти позиции вместе?</p>
                <input type="email" value={email} onChange={e => setEmail(e.target.value)} placeholder="email — пришлём детали"
                  style={{ ...fcInputStyle, fontSize: '15px', letterSpacing: 0 }} />
                <label className="row gap-2" style={{ alignItems: 'flex-start', fontSize: '11px', color: 'var(--ink-muted)', cursor: 'pointer', textAlign: 'left' }}>
                  <input type="checkbox" checked={leadConsent} onChange={e => setLeadConsent(e.target.checked)} style={{ marginTop: '2px' }} />
                  <span>Мне есть 18 лет, согласен с <a href="/terms" target="_blank">офертой</a> и <a href="/privacy" target="_blank">политикой обработки персональных данных</a>.</span>
                </label>
                <button className="btn btn-ghost" style={{ width: '100%', justifyContent: 'center' }} onClick={sendLead}>
                  Получить детали на email
                </button>
                {err && <div className="mono" style={{ fontSize: '12px', color: 'var(--rose)' }}>{err}</div>}
              </>
            )}
            {leadSent && <div className="mono" style={{ fontSize: '12px', color: 'var(--sage)', textAlign: 'center' }}>Готово — детали придут на email ✓</div>}
            <button className="btn btn-primary" style={{ width: '100%', justifyContent: 'center' }} onClick={goOrder}>
              Полный разбор · {rubFmt(catalogPrice('natal', 1990))} <IconArrowRight size={16} />
            </button>
          </div>
        </div>
      )}
    </div>
  );
};

const mxMaskDate = (s) => {
  const d = (s || '').replace(/\D/g, '').slice(0, 8);
  const p = [d.slice(0, 2)];
  if (d.length >= 3) p.push(d.slice(2, 4));
  if (d.length >= 5) p.push(d.slice(4, 8));
  return p.filter(Boolean).join('.');
};

// FreeCalcCard — сам бесплатный расчёт: дата → главный аркан → email → CTA.
//
// Отдельным компонентом, а не куском страницы «Матрица судьбы»: это вход во
// всю freemium-воронку, и он должен стоять там, где на него смотрят. Пока
// карточка жила внутри /matrica, на которую не вело ни одной ссылки, верх
// воронки существовал только для тех, кто знает адрес наизусть.
const FreeCalcCard = () => {
  const calcKind = 'matrix';
  const [dob, setDob] = React.useState('');
  const [result, setResult] = React.useState(null);
  const [calculating, setCalculating] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const [email, setEmail] = React.useState('');
  const [leadConsent, setLeadConsent] = React.useState(false);
  const [leadSent, setLeadSent] = React.useState(false);

  const isoDob = () => {
    const m = (dob || '').match(/^(\d{1,2})[.\-/](\d{1,2})[.\-/](\d{4})$/);
    return m ? `${m[3]}-${m[2].padStart(2, '0')}-${m[1].padStart(2, '0')}` : '';
  };

  const calc = async () => {
    const iso = isoDob();
    if (!iso) {
      // Отказ на валидации — тоже отсев, и его причина отличается от «расчёт
      // упал»: чинится он текстом подсказки, а не кодом.
      window.astro?.track?.('calc_failed', 'validation:date');
      setErr('Введи дату в формате ДД.ММ.ГГГГ'); return;
    }
    setErr(null); setCalculating(true);
    window.astro?.track?.('calc_started', calcKind);
    try {
      const r = await fetch('/api/free/matrix', {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ born_date: iso }),
      });
      const d = await r.json();
      if (!r.ok) throw new Error(d.error || 'Не удалось рассчитать');
      setResult(d);
      window.astro?.track?.('calc_done', calcKind);
    } catch (e) {
      window.astro?.track?.('calc_failed', (e && e.message) || 'unknown');
      setErr(e.message || 'Ошибка');
    } finally { setCalculating(false); }
  };

  const sendLead = async () => {
    if (!email.includes('@')) { setErr('Укажи корректный email'); return; }
    if (!leadConsent) { setErr('Подтверди согласие с условиями'); return; }
    setErr(null);
    try {
      await fetch('/api/free/lead', {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.trim(), kind: 'matrix', born_date: isoDob() }),
      });
    } catch (_) { /* best-effort */ }
    window.astro?.track?.('email_given', calcKind);
    setLeadSent(true);
  };

  const goOrder = () => { window.location.href = '/order/new?product=matrix'; };

  const inputStyle = {
    padding: '14px 16px', borderRadius: '10px', border: '1px solid var(--line)',
    background: 'rgba(255,255,255,0.03)', color: 'var(--ink-primary)', fontSize: '17px',
    textAlign: 'center', letterSpacing: '0.04em', width: '100%',
  };

  // Карточка free-calc: либо форма, либо результат.
  return (
    <div className="card-glass" style={{ padding: '28px', borderRadius: '18px', width: '100%', maxWidth: '420px', position: 'relative', isolation: 'isolate' }}>
      <CardStars seed="matrix-calc" behind />
      {!result ? (
        <div className="col gap-4">
          <div className="label">Бесплатный расчёт</div>
          <input value={dob} onChange={e => setDob(mxMaskDate(e.target.value))}
            placeholder="ДД.ММ.ГГГГ" inputMode="numeric" style={inputStyle} />
          <button className="btn btn-primary" style={{ width: '100%', justifyContent: 'center', opacity: calculating ? 0.6 : 1 }}
            disabled={calculating} onClick={calc}>
            {calculating ? 'Считаем…' : 'Рассчитать бесплатно'}
            {!calculating && <IconArrowRight size={16} />}
          </button>
          {err && <div className="mono" style={{ fontSize: '12px', color: 'var(--rose)' }}>{err}</div>}
          <div className="mono muted" style={{ fontSize: '11px', textAlign: 'center' }}>Без регистрации · результат сразу на экране</div>
        </div>
      ) : (
        <div className="col gap-4">
          <div className="col" style={{ gap: '6px', textAlign: 'center' }}>
            <div className="label">Твой главный аркан</div>
            <div className="display-xl gold" style={{ fontSize: '64px', lineHeight: 1 }}>{result.center?.arcanum}</div>
            <div style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic', fontSize: '22px' }}>{result.center?.name}</div>
          </div>
          <p className="muted" style={{ fontSize: '14px', lineHeight: 1.5, textAlign: 'center' }}>{result.teaser}</p>
          {/* Закрытые точки остаются на своих местах и подписаны: человек должен
              видеть, ЧЕГО ему не показали, иначе закрытая часть не читается как
              ценность. Аркан приходит с сервера только у открытых — вёрстка
              здесь ничего не прячет и прятать не может. */}
          <div className="row" style={{ gap: '8px', flexWrap: 'wrap', justifyContent: 'center' }}>
            {(result.points || []).map(p => (
              <div key={p.code} title={p.title || ''}
                style={{ width: '54px', textAlign: 'center', padding: '8px 4px', borderRadius: '10px',
                  border: p.locked ? '1px dashed var(--line-soft)' : '1px solid var(--line-soft)',
                  opacity: p.locked ? 0.55 : 1 }}>
                <div style={{ fontFamily: 'var(--font-display)', fontSize: '20px', color: 'var(--gold)' }}>
                  {p.locked ? '·' : p.arcanum}
                </div>
                <div className="mono muted" style={{ fontSize: '10px' }}>{p.code}</div>
              </div>
            ))}
          </div>
          <div className="col gap-3" style={{ borderTop: '1px solid var(--line-soft)', paddingTop: '20px' }}>
            {!leadSent && (
              <>
                <p style={{ fontSize: '14px', textAlign: 'center' }}>Открыть остальные {result.locked || 8} точки — предназначение, деньги, отношения, карма?</p>
                <input type="email" value={email} onChange={e => setEmail(e.target.value)} placeholder="email — пришлём детали"
                  style={{ ...inputStyle, fontSize: '15px', letterSpacing: 0 }} />
                <label className="row gap-2" style={{ alignItems: 'flex-start', fontSize: '11px', color: 'var(--ink-muted)', cursor: 'pointer', textAlign: 'left' }}>
                  <input type="checkbox" checked={leadConsent} onChange={e => setLeadConsent(e.target.checked)} style={{ marginTop: '2px' }} />
                  <span>Мне есть 18 лет, согласен с <a href="/terms" target="_blank">офертой</a> и <a href="/privacy" target="_blank">политикой обработки персональных данных</a>.</span>
                </label>
                <button className="btn btn-ghost" style={{ width: '100%', justifyContent: 'center' }} onClick={sendLead}>
                  Получить детали на email
                </button>
              </>
            )}
            {leadSent && <div className="mono" style={{ fontSize: '12px', color: 'var(--sage)', textAlign: 'center' }}>Готово — детали придут на email ✓</div>}
            <button className="btn btn-primary" style={{ width: '100%', justifyContent: 'center' }} onClick={goOrder}>
              Полный разбор · {rubFmt(catalogPrice('matrix', 1490))} <IconArrowRight size={16} />
            </button>
          </div>
        </div>
      )}
    </div>
  );
};

// FreeCalcTabs — два бесплатных расчёта в одном блоке.
//
// Вкладками, а не двумя карточками рядом: рядом они заставляют выбирать до
// того, как человек понял разницу, и половина уходит, не посчитав ничего.
// Натальная карта первой — это основной продукт, а матрица дешевле входит
// (нужна одна дата) и подхватывает тех, кто не знает времени рождения.
const FREE_CALC_TABS = [
  { id: 'natal', label: 'Натальная карта', hint: 'дата, время и место рождения' },
  { id: 'matrix', label: 'Матрица судьбы', hint: 'нужна только дата' },
];

const FreeCalcTabs = ({ initial }) => {
  const [tab, setTab] = React.useState(initial === 'matrix' ? 'matrix' : 'natal');
  return (
    <div className="col gap-4" style={{ width: '100%', maxWidth: '420px' }}>
      <div className="row gap-2" role="tablist" aria-label="Бесплатные расчёты">
        {FREE_CALC_TABS.map(t => (
          <button key={t.id} type="button" role="tab" id={`free-tab-${t.id}`}
            aria-selected={tab === t.id}
            onClick={() => setTab(t.id)}
            className="mono"
            style={{
              flex: 1, padding: '9px 12px', borderRadius: '999px', cursor: 'pointer',
              fontSize: '11px', letterSpacing: '0.06em',
              border: `1px solid ${tab === t.id ? 'var(--gold)' : 'var(--line)'}`,
              background: tab === t.id ? 'rgba(201, 161, 97, 0.08)' : 'none',
              color: tab === t.id ? 'var(--gold)' : 'var(--ink-secondary)',
            }}>
            {t.label}
          </button>
        ))}
      </div>
      <div className="mono muted" style={{ fontSize: '10.5px', textAlign: 'center' }}>
        {(FREE_CALC_TABS.find(t => t.id === tab) || {}).hint}
      </div>
      {tab === 'natal' ? <FreeChartCard /> : <FreeCalcCard />}
    </div>
  );
};

Object.assign(window, { FreeCalcCard, FreeChartCard, FreeCalcTabs });
