// Booking.jsx — 预约填写 + 成功凭证
// Capacity rule: each slot caps at 50. Backend "query" returns booked counts;
// remaining = 50 - booked. remaining<=0 → 已满 (locked). partySize>remaining → blocked.

const CAP = 50;

// 讲解时段：由后端根据日期所在月份查询数据库返回。
function mk(id, range, period) { return { id, range, period, booked: 0 }; }

// 极端兜底（后端完全不可用时）
const FALLBACK_SLOTS = [
  mk('09:30', '09:30 – 10:30', '上午'),
  mk('10:30', '10:30 – 11:30', '上午'),
  mk('11:30', '11:30 – 12:30', '上午'),
  mk('13:30', '13:30 – 14:30', '下午'),
  mk('14:30', '14:30 – 15:30', '下午'),
  mk('15:30', '15:30 – 16:30', '下午'),
];

const WEEKDAYS = ['周日','周一','周二','周三','周四','周五','周六'];

function generateDates() {
  const dates = [];
  const today = new Date();
  for (let i = 0; i < 30; i++) {
    const d = new Date(today);
    d.setDate(today.getDate() + i);
    const y = d.getFullYear();
    const m = d.getMonth() + 1;
    const day = d.getDate();
    const id = `${y}-${String(m).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
    dates.push({ id, d: String(day).padStart(2, '0'), m: m + '月', w: WEEKDAYS[d.getDay()] });
  }
  return dates;
}

function dateLabelOf(id) {
  const d = new Date(id + 'T00:00:00');
  const [y, m, day] = id.split('-');
  const w = WEEKDAYS[d.getDay()];
  return `${y}年${+m}月${+day}日 ${w}`;
}

// ── Local icons not in the kit ──
const X_ICONS = {
  minus: <path d="M5 12h14" />,
  plus: <path d="M12 5v14M5 12h14" />,
  users: <g><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /><circle cx="9" cy="7" r="4" /><path d="M22 21v-2a4 4 0 0 0-3-3.87" /><path d="M16 3.13a4 4 0 0 1 0 7.75" /></g>,
  lock: <g><rect x="3" y="11" width="18" height="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /></g>,
  info: <g><circle cx="12" cy="12" r="10" /><path d="M12 16v-4M12 8h.01" /></g>,
  'circle-check': <g><circle cx="12" cy="12" r="10" /><path d="m9 12 2 2 4-4" /></g>,
  ticket: <g><path d="M2 9a3 3 0 0 1 0 6v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2a3 3 0 0 1 0-6V7a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2Z" /><path d="M13 5v2M13 11v2M13 17v2" /></g>,
  clock: <g><circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" /></g>,
};
function XIcon({ name, size = 20, color = 'currentColor', strokeWidth = 1.5, style = {} }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color}
      strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round"
      style={{ display: 'inline-block', verticalAlign: 'middle', flex: 'none', ...style }}>
      {X_ICONS[name]}
    </svg>
  );
}

// ── Party-size stepper ──
function Stepper({ value, min = 1, max = 50, onChange }) {
  const btn = (dir, disabled, icon) => (
    <button
      onClick={() => !disabled && onChange(value + dir)}
      disabled={disabled}
      style={{
        width: 36, height: 36, borderRadius: 10, flex: 'none',
        border: '1px solid var(--border-1)',
        background: disabled ? 'var(--stone-50)' : '#fff',
        color: disabled ? 'var(--fg-4)' : 'var(--ink-700)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        cursor: disabled ? 'not-allowed' : 'pointer',
        transition: 'background var(--dur-fast) var(--ease-out)',
      }}>
      <XIcon name={icon} size={18} strokeWidth={2} />
    </button>
  );
  return (
    <div style={{
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      background: '#fff', border: '1px solid var(--border-1)', borderRadius: 12, padding: '8px 12px',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <XIcon name="users" size={18} color="var(--brass-500)" />
        <span style={{ fontSize: 14, color: 'var(--fg-1)', fontWeight: 500 }}>预约人数</span>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        {btn(-1, value <= min, 'minus')}
        <span style={{
          minWidth: 24, textAlign: 'center', fontFamily: 'var(--font-mono)',
          fontSize: 20, fontWeight: 500, color: 'var(--fg-1)', fontVariantNumeric: 'tabular-nums',
        }}>{value}</span>
        {btn(1, value >= max, 'plus')}
      </div>
    </div>
  );
}

// ── Date pill ──
function DatePill({ date, active, onClick }) {
  return (
    <button onClick={onClick} style={{
      flex: 'none', width: 56, padding: '8px 4px', borderRadius: 10, cursor: 'pointer',
      border: `1px solid ${active ? 'var(--action)' : 'var(--border-1)'}`,
      background: active ? 'var(--brass-50)' : '#fff',
      boxShadow: active ? '0 0 0 2px var(--action-ring)' : 'none',
      display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1,
      transition: 'all var(--dur-fast) var(--ease-out)',
    }}>
      <span style={{ fontSize: 10, fontWeight: 600, color: active ? 'var(--brass-500)' : 'var(--fg-3)' }}>{date.m}</span>
      <span style={{ fontFamily: 'var(--font-serif)', fontSize: 22, fontWeight: 500, lineHeight: 1, color: active ? 'var(--brass-500)' : 'var(--fg-1)', fontVariationSettings: '"opsz" 36' }}>{date.d}</span>
      <span style={{ fontSize: 10.5, color: active ? 'var(--brass-500)' : 'var(--fg-2)' }}>{date.w}</span>
    </button>
  );
}

// ── Slot card ──
function SlotCard({ slot, partySize, active, onSelect }) {
  const remaining = CAP - slot.booked;
  const full = remaining <= 0;
  const notEnough = !full && partySize > remaining;
  const disabled = full || notEnough;
  const ratio = Math.min(slot.booked / CAP, 1);

  let badge;
  if (full) badge = <Pill kind="rejected" icon="x">已满</Pill>;
  else if (remaining <= 5) badge = <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--crimson-500)' }}>仅剩 {remaining} 个</span>;
  else badge = <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--moss-600)' }}>剩余 {remaining} 个</span>;

  return (
    <button
      onClick={() => !disabled && onSelect()}
      disabled={disabled}
      style={{
        width: '100%', textAlign: 'left', cursor: disabled ? 'not-allowed' : 'pointer',
        background: full ? 'var(--stone-50)' : (active ? 'var(--brass-50)' : '#fff'),
        border: `1px solid ${active ? 'var(--action)' : 'var(--border-1)'}`,
        boxShadow: active ? '0 0 0 2px var(--action-ring)' : 'none',
        borderRadius: 14, padding: '10px 12px',
        display: 'flex', flexDirection: 'column', gap: 8,
        opacity: full ? 0.72 : 1,
        transition: 'all var(--dur-fast) var(--ease-out)',
      }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
          <div style={{
            width: 28, height: 28, borderRadius: 8, flex: 'none',
            background: active ? 'var(--brass-100)' : 'var(--parchment-100)',
            border: '1px solid var(--border-1)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}>
            <XIcon name={full ? 'lock' : 'clock'} size={15} color={full ? 'var(--stone-400)' : 'var(--brass-500)'} />
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 1, minWidth: 0 }}>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 14, fontWeight: 500, color: full ? 'var(--fg-3)' : 'var(--fg-1)', fontVariantNumeric: 'tabular-nums', letterSpacing: '.01em', whiteSpace: 'nowrap' }}>{slot.range}</span>
            <span style={{ fontSize: 11, color: 'var(--fg-2)', whiteSpace: 'nowrap' }}>{slot.period} · 讲解 60 分钟</span>
          </div>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flex: 'none' }}>
          {badge}
          {active && <Icon name="check" size={18} color="var(--brass-500)" strokeWidth={2.2} />}
        </div>
      </div>
      {/* capacity meter */}
      <div>
        <div style={{ height: 5, borderRadius: 999, background: 'var(--stone-100)', overflow: 'hidden' }}>
          <div style={{ width: `${ratio * 100}%`, height: '100%', borderRadius: 999, background: full ? 'var(--crimson-500)' : (remaining <= 5 ? 'var(--brass-400)' : 'var(--moss-500)') }} />
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 6 }}>
          <span style={{ fontSize: 11, color: 'var(--fg-3)', fontVariantNumeric: 'tabular-nums' }}>已报 {slot.booked} / {CAP} 人</span>
          {notEnough && <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--crimson-500)' }}>不足 {partySize} 人席位</span>}
        </div>
      </div>
    </button>
  );
}

// ── Booking screen ──
function BookingScreen({ onBack, onConfirm }) {
  const [party, setParty] = React.useState(1);
  const [phone, setPhone] = React.useState(typeof lastPhone === 'function' ? lastPhone() : '');
  const [dateId, setDateId] = React.useState(null);
  const [slotId, setSlotId] = React.useState(null);
  const [querying, setQuerying] = React.useState(false);
  const [slots, setSlots] = React.useState([]);
  const [dates] = React.useState(() => generateDates());

  // 选择日期后从后端加载该日期的时段余量
  React.useEffect(() => {
    if (!dateId) return;
    async function load() {
      setQuerying(true);
      try {
        const res = await fetch(`/api/availability?date=${dateId}`);
        const json = await res.json().catch(() => ({}));
        if (json.data && json.data.length > 0) {
          setSlots(json.data.map(s => ({
            id: s.id,
            range: s.range,
            period: s.period === 'am' ? '上午' : (s.period === 'pm' ? '下午' : s.period),
            booked: s.booked || 0,
          })));
        } else {
          setSlots([]);
        }
      } catch (e) {
        console.error(e);
        setSlots(FALLBACK_SLOTS.map(s => ({ ...s })));
      }
      setQuerying(false);
    }
    load();
  }, [dateId]);

  const selectedSlot = slots.find(s => s.id === slotId) || null;

  function pickDate(id) {
    if (id === dateId) return;
    setDateId(id);
    setSlotId(null);
  }

  // re-validate selected slot when party size grows past remaining
  React.useEffect(() => {
    if (selectedSlot && party > (CAP - selectedSlot.booked)) setSlotId(null);
  }, [party, selectedSlot]);

  const phoneOk = digits(phone).length === 11;
  const valid = phoneOk && selectedSlot && party <= (CAP - selectedSlot.booked);

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', background: 'var(--bg)' }}>
      <AppHeader
        title="填写预约"
        leading={<button onClick={onBack} style={{ background: 'none', border: 'none', cursor: 'pointer', padding: 2, color: '#fff', display: 'flex' }}><Icon name="chevron-left" size={22} color="#fff" /></button>}
      />

      <div style={{ flex: 1, overflowY: 'auto', WebkitOverflowScrolling: 'touch', padding: '6px 16px 20px', display: 'flex', flexDirection: 'column', gap: 20 }}>
        {/* forum mini-banner */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', background: 'var(--action-soft)', border: '1px solid var(--action-soft-border)', borderRadius: 14, color: 'var(--fg-1)' }}>
          <div style={{ width: 28, height: 28, borderRadius: '50%', background: '#fff', border: '1px solid var(--action-soft-border)', display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 'none' }}><img src="logo.png" style={{ height: 18, width: 18, borderRadius: 4 }} /></div>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 14, fontWeight: 500, fontFamily: 'var(--font-serif)', fontVariationSettings: '"opsz" 24', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{FORUM.title}</div>
            <div style={{ fontSize: 11, color: 'var(--fg-2)', marginTop: 2 }}>{FORUM.location}</div>
          </div>
        </div>

        {/* 1 · phone */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          <SectionHeader>1 · 预约手机号</SectionHeader>
          <PhoneField value={phone} onChange={setPhone} />
          <span style={{ fontSize: 11, color: 'var(--fg-3)', paddingLeft: 2 }}>用于接收预约凭证与查询预约记录。</span>
        </div>

        {/* 2 · party size */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          <SectionHeader>2 · 预约人数</SectionHeader>
          <Stepper value={party} min={1} max={50} onChange={setParty} />
          <span style={{ fontSize: 11, color: 'var(--fg-3)', paddingLeft: 2 }}>单团上限 50 人；10 人以内 200 元/次，超出 10 人按 20 元/人核算（线下收取）。</span>
        </div>

        {/* 3 · date */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          <SectionHeader>3 · 选择日期</SectionHeader>
          <div style={{ display: 'flex', gap: 8, overflowX: 'auto', padding: '2px 16px 4px', margin: '0 -16px', WebkitOverflowScrolling: 'touch', scrollbarWidth: 'none' }}>
            {dates.map(d => <DatePill key={d.id} date={d} active={dateId === d.id} onClick={() => pickDate(d.id)} />)}
          </div>
        </div>

        {/* 4 · slots */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          <SectionHeader>4 · 选择时间段</SectionHeader>

          {!dateId && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '22px 16px', justifyContent: 'center', border: '1px dashed var(--border-1)', borderRadius: 14, color: 'var(--fg-3)' }}>
              <XIcon name="info" size={17} color="var(--fg-3)" />
              <span style={{ fontSize: 13.5 }}>请先选择预约日期。</span>
            </div>
          )}

          {dateId && querying && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '22px 16px', justifyContent: 'center', background: '#fff', border: '1px solid var(--border-1)', borderRadius: 14, color: 'var(--fg-2)' }}>
              <span className="spin" style={{ width: 16, height: 16, borderRadius: '50%', border: '2px solid var(--stone-200)', borderTopColor: 'var(--brass-400)', display: 'inline-block' }} />
              <span style={{ fontSize: 13.5 }}>正在查询各时段余位…</span>
            </div>
          )}

          {dateId && !querying && slots.length > 0 && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {slots.map(s => (
                <SlotCard key={s.id} slot={s} partySize={party} active={slotId === s.id} onSelect={() => setSlotId(s.id)} />
              ))}
              <div style={{ display: 'flex', alignItems: 'center', gap: 6, paddingLeft: 2, marginTop: 2 }}>
                <XIcon name="info" size={13} color="var(--fg-3)" />
                <span style={{ fontSize: 11, color: 'var(--fg-3)' }}>每个讲解时段限 {CAP} 人，满额不可预约。</span>
              </div>
            </div>
          )}

          {dateId && !querying && slots.length === 0 && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '16px 12px', justifyContent: 'center', border: '1px dashed var(--border-1)', borderRadius: 14, color: 'var(--fg-3)' }}>
              <XIcon name="info" size={15} color="var(--fg-3)" />
              <span style={{ fontSize: 12 }}>暂无可用时段，请联系管理员配置。</span>
            </div>
          )}
        </div>
      </div>

      {/* sticky submit */}
      <div style={{ flex: 'none', padding: '10px 16px calc(10px + env(safe-area-inset-bottom))', borderTop: '1px solid var(--border-2)', background: 'var(--bg)', display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 1, flex: 1, minWidth: 0 }}>
          {valid ? (
            <>
              <span style={{ fontSize: 11, fontWeight: 600, letterSpacing: '.1em', textTransform: 'uppercase', color: 'var(--fg-3)' }}>已选</span>
              <span style={{ fontSize: 13, color: 'var(--fg-1)', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{selectedSlot.range} · {party} 人</span>
            </>
          ) : (
            <span style={{ fontSize: 13, color: 'var(--fg-3)' }}>选择人数、日期与时段</span>
          )}
        </div>
        <Button variant="primary" size="lg" disabled={!valid} onClick={() => onConfirm({ party, phone: digits(phone), dateId, dateLabel: dateLabelOf(dateId), slot: selectedSlot })}>提交预约</Button>
      </div>
    </div>
  );
}

// ── Confirmation / voucher ──
function ConfirmScreen({ booking, onDone }) {
  const code = booking.code || genCode();
  const rows = [
    { k: '场馆', v: FORUM.title },
    { k: '日期', v: booking.dateLabel },
    { k: '时段', v: `${booking.slot.range}（${booking.slot.period}）` },
    { k: '人数', v: `${booking.party} 人` },
    { k: '手机', v: fmtPhone(booking.phone) },
  ];
  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', background: 'var(--bg)' }}>
      <div style={{ flex: 1, overflowY: 'auto', padding: '56px 16px 20px', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
        <div className="pop" style={{ width: 56, height: 56, borderRadius: '50%', background: 'var(--moss-50)', border: '1px solid var(--moss-100)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <XIcon name="circle-check" size={28} color="var(--moss-500)" strokeWidth={1.6} />
        </div>
        <h1 style={{ margin: '16px 0 0', fontFamily: 'var(--font-sans)', fontWeight: 600, fontSize: 24, color: 'var(--fg-1)' }}>预约成功</h1>
        <p style={{ margin: '6px 0 0', fontSize: 13, color: 'var(--fg-2)', textAlign: 'center', lineHeight: 1.55, maxWidth: 280 }}>我们已为你保留讲解名额，请提前 10 分钟到服务前台办理讲解手续。</p>

        {/* ticket */}
        <div style={{ width: '100%', marginTop: 22, background: '#fff', border: '1px solid var(--border-1)', borderRadius: 14, overflow: 'hidden' }}>
          <div style={{ padding: '12px 16px', display: 'flex', alignItems: 'center', gap: 8, background: 'var(--action)', color: '#fff' }}>
            <XIcon name="ticket" size={16} color="rgba(255,255,255,0.95)" />
            <span style={{ fontSize: 11, fontWeight: 600, letterSpacing: '.14em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.92)' }}>预约凭证</span>
          </div>
          <div style={{ padding: '4px 16px' }}>
            {rows.map((r, i) => (
              <div key={r.k} style={{ display: 'flex', gap: 12, padding: '11px 0', borderBottom: i < rows.length - 1 ? '1px solid var(--border-2)' : 'none' }}>
                <span style={{ fontSize: 12, color: 'var(--fg-3)', width: 40, flex: 'none' }}>{r.k}</span>
                <span style={{ fontSize: 13, color: 'var(--fg-1)', fontWeight: 500, textAlign: 'right', flex: 1, textWrap: 'pretty' }}>{r.v}</span>
              </div>
            ))}
          </div>
          {/* perforation */}
          <div style={{ position: 'relative', height: 22 }}>
            <div style={{ position: 'absolute', top: '50%', left: 12, right: 12, borderTop: '1px dashed var(--border-1)' }} />
            <div style={{ position: 'absolute', top: '50%', left: -8, transform: 'translateY(-50%)', width: 16, height: 16, borderRadius: '50%', background: 'var(--bg)', border: '1px solid var(--border-1)' }} />
            <div style={{ position: 'absolute', top: '50%', right: -8, transform: 'translateY(-50%)', width: 16, height: 16, borderRadius: '50%', background: 'var(--bg)', border: '1px solid var(--border-1)' }} />
          </div>
          <div style={{ padding: '2px 16px 16px', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6 }}>
            <span style={{ fontSize: 10, fontWeight: 600, letterSpacing: '.14em', textTransform: 'uppercase', color: 'var(--fg-3)' }}>预约编号</span>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 20, fontWeight: 500, letterSpacing: '.08em', color: 'var(--ink-700)' }}>{code}</span>
          </div>
        </div>
      </div>

      <div style={{ flex: 'none', padding: '10px 16px calc(10px + env(safe-area-inset-bottom))', borderTop: '1px solid var(--border-2)', background: 'var(--bg)' }}>
        <Button variant="primary" size="lg" full onClick={onDone}>完成</Button>
      </div>
    </div>
  );
}

Object.assign(window, { BookingScreen, ConfirmScreen });
