/* Личный кабинет — вход по email-коду + дашборд (живые данные из /auth/* и /api/me) */
const ACC_KEY = 'dzagli_account_in';
const ACC_TOKEN_KEY = 'dzagli_token';

/* API на боевом домене; из сред предпросмотра ходим на него же через CORS */
const ACC_API = ['dzagli.space','localhost','127.0.0.1'].includes(location.hostname)
  ? '' : 'https://dzagli.space';

function accGetToken() {
  return localStorage.getItem(ACC_TOKEN_KEY) || sessionStorage.getItem(ACC_TOKEN_KEY) || '';
}
function accSaveToken(token, remember) {
  (remember ? localStorage : sessionStorage).setItem(ACC_TOKEN_KEY, token);
}
function accClearToken() {
  localStorage.removeItem(ACC_TOKEN_KEY);
  sessionStorage.removeItem(ACC_TOKEN_KEY);
}

async function accApi(path, opts = {}) {
  const res = await fetch(ACC_API + path, {
    method: opts.method || 'GET',
    headers: {
      ...(opts.body ? { 'Content-Type': 'application/json' } : {}),
      ...(opts.token ? { 'Authorization': 'Bearer ' + opts.token } : {}),
    },
    body: opts.body ? JSON.stringify(opts.body) : undefined,
  });
  let data = null;
  try { data = await res.json(); } catch (e) {}
  return { status: res.status, data };
}

/* ——— даты/статусы ——— */
const ACC_TZ = 'Asia/Tbilisi';
const ACC_MONTHS = ['ЯНВ','ФЕВ','МАР','АПР','МАЯ','ИЮН','ИЮЛ','АВГ','СЕН','ОКТ','НОЯ','ДЕК'];

function accDate(iso) {
  const d = new Date(iso);
  const parts = new Intl.DateTimeFormat('ru-RU', {
    timeZone: ACC_TZ, day: '2-digit', month: 'numeric',
    weekday: 'short', hour: '2-digit', minute: '2-digit', hour12: false,
  }).formatToParts(d);
  const g = t => (parts.find(p => p.type === t) || {}).value || '';
  return { day: g('day'), mon: ACC_MONTHS[Number(g('month')) - 1] || '',
           dow: g('weekday'), time: g('hour') + ':' + g('minute') };
}

const ACC_BK_STATUS = { accepted:'подтверждено', pending:'ожидает', cancelled:'отменено', rejected:'отклонено' };
const ACC_EV_STATUS = { confirmed:'подтверждено', waitlist:'лист ожидания' };

const ACC_MONTHS_NOM = ['Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'];
const ACC_MONTHS_GEN = ['января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'];
const ACC_DOWS = ['ПН','ВТ','СР','ЧТ','ПТ','СБ','ВС'];

/* 'YYYY-MM-DD' по Тбилиси */
function accDateKey(iso) {
  return new Intl.DateTimeFormat('en-CA', { timeZone: ACC_TZ,
    year:'numeric', month:'2-digit', day:'2-digit' }).format(new Date(iso));
}

/* Канонические названия помещений: все варианты написания → одно имя */
function accNormalizeSpace(raw) {
  const name = (raw || '').split(' между ')[0].trim();
  const n = name.toLowerCase().replace(/[^a-zа-яё]/g, '');
  if (n.includes('black') && n.includes('white')) return 'Black&white scene';
  if (n.includes('tetatet')) return 'Тет-а-тет';
  return name || 'Бронь';
}

/* Цвета помещений: известные — фиксированные, новые — из палитры по порядку появления */
const ACC_PALETTE = ['#C2552B','#2F5FA8','#7A5FA0','#9C8118'];
function accSpaceColors(bookings) {
  const colors = {};
  let i = 0;
  bookings.forEach(b => {
    if (colors[b.space]) return;
    const n = b.space.toLowerCase().replace(/[^a-zа-яё]/g, '');
    if (n.includes('black') && n.includes('white')) colors[b.space] = '#26241C';
    else if (n.includes('tetatet')) colors[b.space] = '#1A8F52';
    else colors[b.space] = ACC_PALETTE[i++ % ACC_PALETTE.length];
  });
  return colors;
}

function accEnrichBooking(b) {
  const s = accDate(b.starts_at), e = accDate(b.ends_at);
  const past = new Date(b.ends_at) < new Date();
  const space = accNormalizeSpace(b.space);
  const hours = (new Date(b.ends_at) - new Date(b.starts_at)) / 3.6e6;
  const dur = Number.isInteger(hours) ? hours + 'ч'
    : String(Math.round(hours * 10) / 10).replace('.', ',') + 'ч';
  return {
    id: b.id, uid: b.uid, space, dateKey: accDateKey(b.starts_at),
    startsMs: +new Date(b.starts_at),
    day: s.day, mon: s.mon, dow: s.dow,
    time: s.time + '–' + e.time, chip: s.time + '·' + dur,
    kind: b.place || '',
    price: b.price != null ? b.price + ' ₾' : '',
    status: past && b.status === 'accepted' ? 'завершено' : (ACC_BK_STATUS[b.status] || b.status),
    cancelled: b.status === 'cancelled' || b.status === 'rejected',
    past,
  };
}

function accMapEvent(ev) {
  const s = accDate(ev.starts_at);
  const past = new Date(ev.starts_at) < new Date();
  return {
    id: ev.id, title: ev.title, day: s.day, mon: s.mon, dow: s.dow,
    time: s.time, place: ev.place || '',
    status: ACC_EV_STATUS[ev.status] || ev.status, past,
  };
}

function accInitials(name) {
  return (name || '?').trim().split(/\s+/).slice(0, 2).map(w => w[0]).join('').toUpperCase();
}

function AccArr() { return <svg width="16" height="16" viewBox="0 0 18 18" fill="none"><path d="M3 9h11M10 4l5 5-5 5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/></svg>; }
function AccAvatar({ name, size=54 }) {
  return <div className="cab-avatar" style={{ width:size, height:size, fontSize:Math.round(size*0.36) }}>{accInitials(name)}</div>;
}

/* ——— дашборд ——— */
function AccBookingCard({ b, onCancel }) {
  const [confirming, setConfirming] = useState(false);
  const [cancelling, setCancelling] = useState(false);
  const [cancelError, setCancelError] = useState(false);

  async function doCancel() {
    setCancelling(true);
    setCancelError(false);
    const ok = await onCancel(b.id, b.uid);
    setCancelling(false);
    if (ok) { setConfirming(false); }
    else { setCancelError(true); }
  }

  const canCancel = !b.past && !b.cancelled;

  return (
    <div className={'cab-card'+(b.past||b.cancelled?' is-past':'')}>
      {canCancel && (
        <button className="cab-card__close" aria-label="Отменить бронь" onClick={() => { setConfirming(v => !v); setCancelError(false); }}>
          <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
            <path d="M1 1l8 8M9 1L1 9" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/>
          </svg>
        </button>
      )}
      <div className="cab-card__date">
        <span className="serif" style={{ fontSize:30, lineHeight:1 }}>{b.day}</span>
        <span className="mono faint" style={{ fontSize:10.5, letterSpacing:'0.08em' }}>{b.mon}</span>
      </div>
      <div style={{ flex:1, minWidth:0 }}>
        <div className="flex gap-s center" style={{ marginBottom:6, flexWrap:'wrap' }}>
          <span className="cab-tag cab-tag--green">аренда</span>
          <span className={'cab-status'+(b.cancelled?' is-cancelled':(b.past?' is-done':''))}>{b.status}</span>
        </div>
        <div className="mono" style={{ fontSize:15, marginBottom:3 }}>{b.dow} · {b.time}</div>
        <div className="serif faint" style={{ fontSize:16, lineHeight:1.1 }}>{b.space}</div>
      </div>
      {b.price && <span className="serif" style={{ fontSize:18, color: b.past?'var(--ink-faint)':'var(--green)', whiteSpace:'nowrap' }}>{b.price}</span>}
      {confirming && (
        <div style={{ position:'absolute', bottom:10, right:12, display:'flex', alignItems:'center', gap:6 }}>
          {cancelError
            ? <span className="mono" style={{ fontSize:11, color:'var(--rust)' }}>не удалось — попробуй ещё раз</span>
            : <span className="mono faint" style={{ fontSize:11 }}>Отменить бронь?</span>}
          <button className="cab-mini-link mono" style={{ fontSize:11, color:'var(--rust)' }}
            disabled={cancelling} onClick={doCancel}>{cancelling ? '…' : 'Да'}</button>
          <button className="cab-mini-link mono" style={{ fontSize:11 }}
            onClick={() => { setConfirming(false); setCancelError(false); }}>Нет</button>
        </div>
      )}
    </div>
  );
}

function AccEventCard({ e }) {
  return (
    <div className={'cab-card'+(e.past?' is-past':'')}>
      <div className="cab-card__date">
        <span className="serif" style={{ fontSize:30, lineHeight:1 }}>{e.day}</span>
        <span className="mono faint" style={{ fontSize:10.5, letterSpacing:'0.08em' }}>{e.mon}</span>
      </div>
      <div style={{ flex:1, minWidth:0 }}>
        <div className="flex gap-s center" style={{ marginBottom:5 }}>
          <span className="cab-tag cab-tag--rust">событие</span>
          <span className={'cab-status'+(e.past?' is-done':'')}>{e.status}</span>
        </div>
        <div className="serif" style={{ fontSize:18, lineHeight:1.1 }}>{e.title}</div>
        <div className="mono faint" style={{ fontSize:12, marginTop:5 }}>{e.dow} · {e.time}{e.place ? ' · '+e.place : ''}</div>
      </div>
    </div>
  );
}

/* ——— календарь-планер броней ——— */
function AccCalendar({ bookings, colors, selected, onSelect }) {
  const todayKey = accDateKey(new Date().toISOString());
  const [ym, setYm] = useState(() => {
    /* по умолчанию — месяц ближайшей активной брони */
    const next = bookings.filter(b => !b.past).sort((a, b) => a.startsMs - b.startsMs)[0];
    const k = next ? next.dateKey : todayKey;
    return { y: +k.slice(0, 4), m: +k.slice(5, 7) - 1 };
  });

  const byDate = {};
  bookings.forEach(b => { (byDate[b.dateKey] = byDate[b.dateKey] || []).push(b); });
  Object.values(byDate).forEach(a => a.sort((x, y) => x.startsMs - y.startsMs));

  const offset = (new Date(ym.y, ym.m, 1).getDay() + 6) % 7; /* ПН=0 */
  const dim = new Date(ym.y, ym.m + 1, 0).getDate();
  const dimPrev = new Date(ym.y, ym.m, 0).getDate();
  const total = Math.ceil((offset + dim) / 7) * 7;
  const pad2 = n => String(n).padStart(2, '0');

  function shift(d) {
    setYm(({ y, m }) => ({ y: y + Math.floor((m + d) / 12), m: (m + d + 12) % 12 }));
  }

  const cells = [];
  for (let i = 0; i < total; i++) {
    const dnum = i - offset + 1;
    const out = dnum < 1 || dnum > dim;
    const shown = dnum < 1 ? dimPrev + dnum : dnum > dim ? dnum - dim : dnum;
    const key = out ? null : `${ym.y}-${pad2(ym.m + 1)}-${pad2(dnum)}`;
    const dayBk = key ? (byDate[key] || []) : [];
    const chips = dayBk.length > 3 ? dayBk.slice(0, 2) : dayBk;
    const cls = 'cab-cal__cell'
      + (out ? ' is-out' : ' is-click')
      + (key && key === selected ? ' is-sel' : '')
      + (key === todayKey ? ' is-today' : '');
    const toggle = () => onSelect(key === selected ? null : key);
    cells.push(
      <div key={i} className={cls}
        role={out ? undefined : 'button'} tabIndex={out ? undefined : 0}
        onClick={out ? undefined : toggle}
        onKeyDown={out ? undefined : e => {
          if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); }
        }}>
        <span className={'cab-cal__num' + (dayBk.length ? ' has-bk' : '')}>{shown}</span>
        {chips.map(b => (
          <span key={b.id} className={'cab-cal__chip' + (b.past ? ' is-past' : '')}
            style={{ background: colors[b.space] }}
            title={b.space + ' · ' + b.time}>{b.chip}</span>
        ))}
        {dayBk.length > 3 && <span className="cab-cal__more">+{dayBk.length - 2} ещё</span>}
      </div>
    );
  }

  /* только помещения из списка аренд пользователя (предстоящих и прошедших) */
  const spaces = [...new Set(bookings.map(b => b.space).filter(Boolean))];

  return (
    <div className="cab-cal">
      <div className="cab-cal__head">
        <button className="cab-cal__nav" aria-label="Предыдущий месяц" onClick={() => shift(-1)}>
          <svg width="14" height="14" viewBox="0 0 18 18" fill="none"><path d="M15 9H4M8 4L3 9l5 5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </button>
        <span className="cab-cal__title">{ACC_MONTHS_NOM[ym.m]} {ym.y}</span>
        <button className="cab-cal__nav" aria-label="Следующий месяц" onClick={() => shift(1)}>
          <AccArr/>
        </button>
      </div>
      <div className="cab-cal__dows">{ACC_DOWS.map(d => <span key={d} className="cab-cal__dow">{d}</span>)}</div>
      <div className="cab-cal__grid">{cells}</div>
      <div className="cab-cal__legend">
        {spaces.map(s => (
          <span key={s} className="cab-cal__legend-item">
            <span className="cab-cal__swatch" style={{ background: colors[s] }}></span>{s}
          </span>
        ))}
        <span className="cab-cal__legend-item">
          <span className="cab-cal__swatch" style={{ background: 'var(--ink)', opacity: 0.32 }}></span>прошедшая
        </span>
        <span className="cab-cal__legend-item">
          <span className="cab-cal__today-box"></span>сегодня
        </span>
      </div>
    </div>
  );
}

function AccDash({ go, onLogout, me }) {
  const [tab, setTab] = useState('bookings');
  const [selDay, setSelDay] = useState(null);
  const [cancelledIds, setCancelledIds] = useState(new Set());
  const nav = [['bookings','Брони'],['events','События'],['profile','Профиль']];

  if (!me) {
    return (
      <div className="wrap section-pad">
        <div className="eyebrow eyebrow--green" style={{ marginBottom:20 }}>личный кабинет</div>
        <p className="mono faint">загружаем…</p>
      </div>
    );
  }

  /* отменённые в сессии помечаем сразу, до перезапроса Cal.com */
  const bookings = me.bookings.map(accEnrichBooking).map(b =>
    cancelledIds.has(b.id) ? { ...b, cancelled: true, status: 'отменено' } : b);
  const live = bookings.filter(b => !b.cancelled); /* на календаре только активные */
  const colors = accSpaceColors(live);
  const events = me.events.map(accMapEvent);
  const upBk = live.filter(b => !b.past).length;
  const upEv = events.filter(e => !e.past).length;

  async function handleCancel(bookingId, bookingUid) {
    const { status, data } = await accApi(`/api/bookings/${bookingUid}/cancel`,
      { method: 'POST', token: accGetToken() });
    const ok = status === 200 && data?.ok;
    if (ok) setCancelledIds(prev => new Set([...prev, bookingId]));
    return ok;
  }

  /* список под календарём: выбранный день (активные) либо все —
     будущие по возрастанию, затем прошедшие и отменённые по убыванию */
  const dayList = selDay ? live.filter(b => b.dateKey === selDay).sort((a,b) => a.startsMs - b.startsMs) : null;
  const allList = [
    ...live.filter(b => !b.past).sort((a,b) => a.startsMs - b.startsMs),
    ...bookings.filter(b => b.past || b.cancelled).sort((a,b) => b.startsMs - a.startsMs),
  ];
  const ctxLabel = selDay
    ? 'брони на ' + parseInt(selDay.slice(8,10), 10) + ' ' + ACC_MONTHS_GEN[+selDay.slice(5,7) - 1]
    : 'все брони';

  return (
    <div className="wrap section-pad">
      <div className="eyebrow eyebrow--green" style={{ marginBottom:20 }}>личный кабинет</div>
      <div className="cab cab-dash">
        <aside className="cab-side">
          <AccAvatar name={me.user.name} size={72}/>
          <h3 style={{ fontSize:24, marginTop:16, lineHeight:1.05 }}>{me.user.name}</h3>
          <div className="mono faint" style={{ fontSize:12, marginTop:8 }}>{me.user.email}</div>
          <div className="cab-stat">
            <div><span className="cab-stat__n">{upBk}</span><span className="cab-stat__l mono">брони</span></div>
            <div><span className="cab-stat__n">{upEv}</span><span className="cab-stat__l mono">события</span></div>
          </div>
          <nav className="cab-side__nav">
            {nav.map(([id,l])=>(
              <button key={id} className={'cab-navitem'+(tab===id?' is-on':'')} onClick={()=>setTab(id)}>
                {l} {tab===id && <AccArr/>}
              </button>
            ))}
            <button className="cab-navitem cab-navitem--out" onClick={onLogout}>Выйти</button>
          </nav>
        </aside>

        <main>
          {tab==='bookings' && (
            <React.Fragment>
              <div className="cab-sechead" style={{ marginBottom:16 }}>
                <span className="cab-sechead__label">Мои брони</span>
                <span className="mono faint" style={{ fontSize:12 }}>{upBk} активных</span>
                <hr className="rule rule--soft" style={{ flex:1 }}/>
              </div>
              <AccCalendar bookings={live} colors={colors} selected={selDay} onSelect={setSelDay}/>
              <div className="cab-ctx">
                <span>{ctxLabel}</span>
                {selDay && <button className="cab-mini-link mono" style={{ fontSize:12 }} onClick={()=>setSelDay(null)}>показать все</button>}
              </div>
              {selDay
                ? (dayList.length
                    ? <div className="cab-cards">{dayList.map(b=> <AccBookingCard key={b.id} b={b} onCancel={handleCancel}/>)}</div>
                    : <p className="mono faint" style={{ fontSize:13 }}>На этот день броней нет — выберите день с плашкой или нажмите «показать все».</p>)
                : (allList.length
                    ? <div className="cab-cards">{allList.map(b=> <AccBookingCard key={b.id} b={b} onCancel={handleCancel}/>)}</div>
                    : <p className="mono faint" style={{ fontSize:13 }}>Пока нет броней.</p>)}
              <button className="btn btn--ghost" style={{ marginTop:22 }} onClick={()=>go('rental')}>Забронировать ещё <AccArr/></button>
            </React.Fragment>
          )}

          {tab==='events' && (
            <React.Fragment>
              <div className="cab-sechead" style={{ marginBottom:16 }}>
                <span className="cab-sechead__label">Мои события</span>
                <span className="mono faint" style={{ fontSize:12 }}>{upEv} впереди</span>
                <hr className="rule rule--soft" style={{ flex:1 }}/>
              </div>
              {events.length
                ? <div className="cab-cards">{events.map(e=> <AccEventCard key={e.id} e={e}/>)}</div>
                : <p className="mono faint" style={{ fontSize:13 }}>Пока нет записей на события.</p>}
              <button className="btn btn--ghost" style={{ marginTop:22 }} onClick={()=>go('feed')}>Вся афиша <AccArr/></button>
            </React.Fragment>
          )}

          {tab==='profile' && (
            <React.Fragment>
              <div className="cab-sechead" style={{ marginBottom:16 }}>
                <span className="cab-sechead__label">Профиль</span>
                <hr className="rule rule--soft" style={{ flex:1 }}/>
              </div>
              <div className="acc-field"><span className="cab-label mono">Имя</span><div className="cab-input"><span>{me.user.name}</span></div></div>
              <div className="acc-field" style={{ marginTop:16 }}><span className="cab-label mono">Email</span><div className="cab-input"><span>{me.user.email}</span></div></div>
              <div className="flex gap-s" style={{ marginTop:22, flexWrap:'wrap' }}>
                <button className="btn btn--ghost" onClick={onLogout}>Выйти</button>
              </div>
            </React.Fragment>
          )}
        </main>
      </div>
    </div>
  );
}

/* ——— вход по email-коду ——— */
function AccCodeInputs({ code, setCode }) {
  const refs = useRef([]);
  function set(i, v) {
    v = (v.match(/\d/g) || []).pop() || '';
    const next = [...code]; next[i] = v; setCode(next);
    if (v && i < 3 && refs.current[i+1]) refs.current[i+1].focus();
  }
  return (
    <div className="cab-otp">
      {code.map((d,i)=>(
        <input key={i} ref={el=>refs.current[i]=el}
          className={'cab-otp__box'+(d?' is-filled':'')}
          value={d} inputMode="numeric" maxLength={1} aria-label={'цифра '+(i+1)}
          onChange={e=>set(i, e.target.value)}
          onKeyDown={e=>{ if(e.key==='Backspace' && !code[i] && i>0 && refs.current[i-1]) refs.current[i-1].focus(); }} />
      ))}
    </div>
  );
}

function AccLogin({ stage, setStage, email, setEmail, remember, setRemember,
                    code, setCode, onSend, onLogin, busy, error }) {
  return (
    <div className="acc-loginwrap">
      <div className="acc-card cab">
        <div className="brand" style={{ marginBottom:26 }}>
          <span className="brand__dot"></span>
          <span className="brand__mark">Бродячая Собака</span>
        </div>

        {stage==='email' ? (
          <React.Fragment>
            <h2 style={{ fontSize:30, marginBottom:10 }}>Вход в кабинет</h2>
            <p className="muted prettyw" style={{ fontSize:15, marginBottom:22, maxWidth:'34ch' }}>
              Введите email — пришлём код для входа. Регистрация не нужна, аккаунт создаётся сам.
            </p>
            <label className="cab-label mono">Email</label>
            <input className="cab-input cab-input--field" value={email} onChange={e=>setEmail(e.target.value)}
              type="email" inputMode="email" placeholder="you@example.com"
              onKeyDown={e=>{ if(e.key==='Enter') onSend(); }} />
            <button type="button" className="acc-toggle" onClick={()=>setRemember(r=>!r)} style={{ marginTop:18 }}>
              <span className={'cab-switch'+(remember?' is-on':'')}><span className="cab-switch__knob"></span></span>
              <span>Оставаться в системе <span className="faint">· ~90 дней</span></span>
            </button>
            {error && <p className="mono" style={{ fontSize:12, marginTop:14, color:'var(--rust, #b4533a)' }}>{error}</p>}
            <button className="btn btn--green" style={{ width:'100%', justifyContent:'center', marginTop:20 }}
              disabled={busy} onClick={onSend}>{busy?'Отправляем…':'Получить код'} <AccArr/></button>
            <p className="mono faint" style={{ fontSize:11, marginTop:18, textAlign:'center', lineHeight:1.5 }}>
              Нажимая «Получить код», вы соглашаетесь<br/>с правилами дома
            </p>
          </React.Fragment>
        ) : (
          <React.Fragment>
            <h2 style={{ fontSize:30, marginBottom:10 }}>Введите код</h2>
            <p className="muted prettyw" style={{ fontSize:15, marginBottom:22, maxWidth:'34ch' }}>
              Отправили 4-значный код на <span style={{ color:'var(--ink)' }}>{email}</span>. Проверьте почту.
            </p>
            <AccCodeInputs code={code} setCode={setCode} />
            {error && <p className="mono" style={{ fontSize:12, marginTop:14, color:'var(--rust, #b4533a)' }}>{error}</p>}
            <button className="btn btn--green" style={{ width:'100%', justifyContent:'center', marginTop:22 }}
              disabled={busy} onClick={onLogin}>{busy?'Проверяем…':'Войти'} <AccArr/></button>
            <div className="flex center between" style={{ marginTop:18 }}>
              <button className="mono faint" style={{ fontSize:11.5 }} onClick={()=>setStage('email')}>← Изменить email</button>
              <button className="cab-mini-link mono" style={{ fontSize:11.5 }} onClick={onSend}>Отправить ещё раз</button>
            </div>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

function Account({ go }) {
  const [stage, setStage] = useState(() => accGetToken() ? 'in' : 'email');
  const [email, setEmail] = useState('');
  const [remember, setRemember] = useState(true);
  const [code, setCode] = useState(['','','','']);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState('');
  const [me, setMe] = useState(null);

  function reset() {
    accClearToken();
    localStorage.removeItem(ACC_KEY);
    setMe(null); setCode(['','','','']); setError(''); setStage('email');
    window.dispatchEvent(new Event('authchange'));
  }

  useEffect(() => {
    if (stage !== 'in') return;
    let alive = true;
    accApi('/api/me', { token: accGetToken() }).then(({ status, data }) => {
      if (!alive) return;
      if (status === 200 && data && data.user) setMe(data);
      else reset(); // токен истёк/невалиден
    }).catch(() => { if (alive) setMe(null); });
    return () => { alive = false; };
  }, [stage]);

  async function sendCode() {
    setError('');
    setBusy(true);
    try {
      const { status } = await accApi('/auth/code', { method:'POST', body:{ email: email.trim() } });
      if (status === 200) { setCode(['','','','']); setStage('code'); }
      else if (status === 429) setError('Слишком много запросов — попробуйте через час.');
      else setError('Проверьте email — похоже, в нём опечатка.');
    } catch (e) { setError('Не получилось связаться с сервером. Попробуйте ещё раз.'); }
    setBusy(false);
  }

  async function login() {
    setError('');
    const codeStr = code.join('');
    if (codeStr.length < 4) { setError('Введите все 4 цифры кода.'); return; }
    setBusy(true);
    try {
      const { status, data } = await accApi('/auth/verify',
        { method:'POST', body:{ email: email.trim(), code: codeStr, remember } });
      if (status === 200 && data && data.ok) {
        accSaveToken(data.token, remember);
        localStorage.setItem(ACC_KEY, '1');
        setStage('in');
        window.dispatchEvent(new Event('authchange'));
      } else {
        setError('Неверный или устаревший код. Проверьте почту или запросите новый.');
        setCode(['','','','']);
      }
    } catch (e) { setError('Не получилось связаться с сервером. Попробуйте ещё раз.'); }
    setBusy(false);
  }

  function logout() {
    const token = accGetToken();
    if (token) accApi('/auth/logout', { method:'POST', token }).catch(()=>{});
    reset();
  }

  if (stage==='in') return <AccDash go={go} onLogout={logout} me={me} />;
  return <AccLogin stage={stage} setStage={setStage} email={email} setEmail={setEmail}
    remember={remember} setRemember={setRemember} code={code} setCode={setCode}
    onSend={sendCode} onLogin={login} busy={busy} error={error} />;
}

Object.assign(window, { Account });
