/* global React, Icon, UI, LessonHighData */
// ============================================================
// I4 + I5 — Mobile preview
//   Single component supports two modes:
//     - 'member'  : 5-tab (\uc624\ub298 / \uc77c\uc9c0 / \uc608\uc57d / \uacb0\uc81c / \ub179\uc74c)
//     - 'parent'  : 3-tab (\uc790\ub140 / \uc54c\ub9bc / \uacb0\uc81c)
//   Verify gate kept (same as v3). A small switch at the top of the
//   verify screen lets the demo viewer flip member <-> parent.
// ============================================================
(function () {
const { useState, useEffect, useMemo } = React;
const Dm = LessonHighData;

function MobileApp({ initialMemberId = 'm14' }) {
  const [role, setRole] = useState('member'); // 'member' | 'parent'
  const [stage, setStage] = useState('verify');

  // Default the parent view to '박서영' (g1) since she has two kids — best demo
  const [memberId, setMemberId]   = useState(initialMemberId);
  const [guardianId, setGuardianId] = useState('g1');

  useEffect(() => { setStage('verify'); }, [initialMemberId, role]);

  const m = Dm.getMember(memberId);
  const g = Dm.getGuardian ? Dm.getGuardian(guardianId) : null;

  return (
    <div className="phone__screen mob">
      <div style={{
        height: 44, padding: '0 28px',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        fontSize: 13, fontWeight: 600, fontFamily: 'var(--font-mono)', flexShrink: 0,
      }}>
        <span>9:41</span>
        <span style={{ display: 'inline-flex', gap: 4, alignItems: 'center' }}>
          <span style={{ display: 'inline-block', width: 16, height: 10, border: '1px solid var(--text-primary)', borderRadius: 2, position: 'relative' }}>
            <span style={{ position: 'absolute', inset: 1, background: 'var(--text-primary)', width: '70%' }}/>
          </span>
        </span>
      </div>

      {stage === 'verify' && (
        <VerifyScreen
          role={role} setRole={setRole}
          member={m} guardian={g}
          onPass={() => setStage('home')}
        />
      )}
      {stage === 'home' && role === 'member' && (
        <MemberHome member={m} onLock={() => setStage('verify')} onSwitchRole={() => { setRole('parent'); setStage('verify'); }}/>
      )}
      {stage === 'home' && role === 'parent' && (
        <ParentHome guardian={g} onLock={() => setStage('verify')} onSwitchRole={() => { setRole('member'); setStage('verify'); }}/>
      )}
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// Verify gate (mode switcher lives here)
// ────────────────────────────────────────────────────────────
function VerifyScreen({ role, setRole, member, guardian, onPass }) {
  return (
    <div style={{ flex: 1, padding: '20px 20px 24px', display: 'flex', flexDirection: 'column', overflow: 'auto' }}>
      <div className="row" style={{ gap: 10, marginBottom: 18 }}>
        <span style={{ width: 32, height: 32, background: 'var(--accent-default)', color: 'var(--text-on-accent)', borderRadius: 8, display: 'grid', placeItems: 'center', fontFamily: 'var(--font-mono)', fontWeight: 700 }}>R</span>
        <div className="col" style={{ gap: 0 }}>
          <span style={{ fontSize: 13, fontWeight: 600 }}>송유이보컬발성클래스</span>
          <span style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>{role === 'parent' ? '학부모 페이지' : '학생 정보 페이지'}</span>
        </div>
      </div>

      {/* Role toggle (demo) */}
      <div className="mob-roles">
        <button className={`mob-roles__btn ${role === 'member' ? 'is-active' : ''}`} onClick={() => setRole('member')}>
          <Icon.User size={12}/><span>회원</span>
        </button>
        <button className={`mob-roles__btn ${role === 'parent' ? 'is-active' : ''}`} onClick={() => setRole('parent')}>
          <Icon.Users size={12}/><span>학부모</span>
        </button>
      </div>

      <div style={{ background: 'var(--bg-surface)', border: '1px solid var(--border-default)', borderRadius: 16, padding: 22 }}>
        <div className="t-h2" style={{ marginBottom: 6 }}>본인 확인</div>
        <div style={{ fontSize: 13.5, color: 'var(--text-secondary)', marginBottom: 18, lineHeight: 1.5 }}>
          {role === 'member' ? '안전한 접근을 위해 학생 정보를 확인합니다.' : '학부모님 본인 확인을 진행합니다.'}
        </div>

        {role === 'member' ? (
          <React.Fragment>
            <div className="field" style={{ marginBottom: 12 }}>
              <label className="field__label">학생 이름</label>
              <input className="input" style={{ height: 42, fontSize: 15 }} defaultValue={member?.name || ''}/>
            </div>
            <div className="field" style={{ marginBottom: 18 }}>
              <label className="field__label">학생 생년월일</label>
              <input className="input" style={{ height: 42, fontSize: 15 }} defaultValue={member?.birth || ''}/>
            </div>
          </React.Fragment>
        ) : (
          <React.Fragment>
            <div className="field" style={{ marginBottom: 12 }}>
              <label className="field__label">학부모 이름</label>
              <input className="input" style={{ height: 42, fontSize: 15 }} defaultValue={guardian?.name || ''}/>
            </div>
            <div className="field" style={{ marginBottom: 18 }}>
              <label className="field__label">전화번호 뒷자리 4글자</label>
              <input className="input" style={{ height: 42, fontSize: 15 }} defaultValue={(guardian?.phone || '').slice(-4)}/>
            </div>
          </React.Fragment>
        )}

        <UI.Button block variant="primary" size="lg" onClick={onPass}>확인</UI.Button>
      </div>

      <ul style={{ listStyle: 'none', margin: '20px 0 0', padding: 0, fontSize: 12, color: 'var(--text-tertiary)', lineHeight: 1.7 }}>
        <li>※ 본 페이지는 송유이보컬발성클래스가 발송한 안전한 링크입니다.</li>
        <li>※ 정보가 일치하지 않으면 학원에 문의하세요.</li>
        <li>※ 5회 이상 실패 시 24시간 잠금됩니다.</li>
      </ul>
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// I4 · MEMBER HOME — 5 tabs
// ────────────────────────────────────────────────────────────
function MemberHome({ member, onLock, onSwitchRole }) {
  const [tab, setTab] = useState('today');
  return (
    <div className="mob-shell">
      <div className="mob-shell__body">
        <div className="mob-shell__ctx">
          <Icon.Layers size={12}/>
          <span>이 페이지는 <strong style={{ color: 'var(--text-primary)' }}>{member.name}</strong>님의 정보입니다</span>
          <button onClick={onSwitchRole} className="mob-shell__role">학부모 뷰 →</button>
          <button onClick={onLock} className="mob-shell__lock">잠금</button>
        </div>
        {tab === 'today'   && <MemTodayTab    member={member}/>}
        {tab === 'journal' && <MemJournalTab  member={member}/>}
        {tab === 'book'    && <MemBookTab     member={member}/>}
        {tab === 'pay'     && <MemPayTab      member={member}/>}
        {tab === 'rec'     && <MemRecordTab   member={member}/>}
      </div>
      <nav className="mob-tabs">
        {[
          { id: 'today',   label: '오늘', icon: Icon.Home },
          { id: 'journal', label: '일지', icon: Icon.Note },
          { id: 'book',    label: '예약', icon: Icon.Calendar },
          { id: 'pay',     label: '결제', icon: Icon.Card },
          { id: 'rec',     label: '녹음', icon: Icon.Mobile },
        ].map(t => (
          <button key={t.id} className={`mob-tab ${tab === t.id ? 'is-active' : ''}`} onClick={() => setTab(t.id)}>
            <t.icon size={16}/>
            <span>{t.label}</span>
          </button>
        ))}
      </nav>
    </div>
  );
}

// — Tab: 오늘
function MemTodayTab({ member }) {
  const next = Dm.reservations.filter(r => r.memberId === member.id).sort((a,b) => a.dow - b.dow || a.start - b.start)[0];
  const t    = next ? Dm.getTeacher(next.teacherId) : null;
  const room = next ? Dm.getRoom(next.roomId) : null;
  const due  = Dm.payments.find(p => p.memberId === member.id);

  // I7 — most recent sent announcement targeted at members
  const recentAnn = (Dm.announcements || [])
    .filter(a => a.status === Dm.Enums.AnnouncementStatus.SENT && (a.audience.recipients === 'member' || a.audience.recipients === 'both'))
    .sort((a, b) => (b.sentAt || '').localeCompare(a.sentAt || ''))[0];

  return (
    <div className="mob-tab-body">
      <div className="mob-hero">
        <div style={{ fontSize: 12, opacity: 0.7, fontWeight: 500 }}>안녕하세요</div>
        <div style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-0.02em' }}>{member.name}님</div>
        <div style={{ fontSize: 12, opacity: 0.8, marginTop: 4 }}>
          {Dm.getTeacher(member.teacherId).name} 선생님 · {member.passType === 'SESSION' ? `${member.total}회권` : '기간권'}
        </div>
      </div>

      {recentAnn && (
        <div className="mob-card" style={{ borderLeft: '3px solid var(--accent-default)', padding: '10px 12px' }}>
          <div className="row" style={{ marginBottom: 4 }}>
            <UI.Badge tone="accent" dot>공지</UI.Badge>
            {Dm.getAnnouncementCategory && (
              <span className={`ann-cat-chip ann-cat-${recentAnn.category}`} style={{ fontSize: 10, padding: '1px 6px' }}>
                {Dm.getAnnouncementCategory(recentAnn.category)?.label}
              </span>
            )}
            <span className="t-mono num t-caption" style={{ fontSize: 11, marginLeft: 'auto' }}>{shortAnnTime(recentAnn.sentAt)}</span>
          </div>
          <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 2 }}>{recentAnn.title}</div>
          <div className="t-caption" style={{ fontSize: 11.5, lineHeight: 1.5 }}>
            {recentAnn.body.length > 90 ? recentAnn.body.slice(0, 90) + '…' : recentAnn.body}
          </div>
        </div>
      )}

      {next && (
        <div className="mob-card mob-card--accent">
          <div className="t-micro" style={{ color: 'var(--accent-default)', marginBottom: 4 }}>다음 수업</div>
          <div className="t-mono num" style={{ fontSize: 18, fontWeight: 700, color: 'var(--accent-default)' }}>
            {Dm.dayNames[next.dow]}요일 · {Dm.formatTime(next.start)}
          </div>
          <div style={{ fontSize: 12.5, color: 'var(--text-secondary)', marginBottom: 12 }}>
            {room?.name} · {t?.name} 선생님
          </div>
          <div className="row" style={{ gap: 6 }}>
            <UI.Button size="sm" variant="outline" icon={Icon.Refresh}>시간 변경</UI.Button>
            <UI.Button size="sm" variant="ghost">결석 알림</UI.Button>
          </div>
        </div>
      )}

      <div className="mob-grid-2">
        <MobTile label="수강권" value={`${member.remaining}`} sub={`/ ${member.total}회`} accent
          bar={member.remaining / member.total}/>
        {due ? (
          <MobTile label="다음 결제" value={Dm.formatRelative(due.dueDate)} sub={Dm.formatMoney(due.amount)} warn/>
        ) : (
          <MobTile label="다음 결제" value="—" sub="예정 없음"/>
        )}
      </div>

      <div className="mob-card">
        <div className="row" style={{ marginBottom: 8 }}>
          <span className="t-micro">최근 일지</span>
          <span className="t-caption" style={{ marginLeft: 'auto', fontSize: 11 }}>{Dm.lessonNotes.filter(n => n.memberId === member.id).length}건</span>
        </div>
        {(Dm.lessonNotes.find(n => n.memberId === member.id) || null) ? (
          <MiniNotePeek note={Dm.lessonNotes.find(n => n.memberId === member.id)}/>
        ) : <div className="t-caption">아직 일지가 없습니다.</div>}
      </div>
    </div>
  );
}

// — Tab: 일지 (timeline + media)
function MemJournalTab({ member }) {
  const notes = Dm.lessonNotes.filter(n => n.memberId === member.id);
  const recentTeacher = Dm.getTeacher(member.teacherId);
  const openKakao = () => window.toast && window.toast(`카카오톡 채널 ${Dm.settings.kakaoChannelHandle}이 열립니다`, { tone: 'success' });
  const openCall = () => window.toast && window.toast(`${Dm.settings.supportPhone}로 전화 앱이 열립니다`);
  return (
    <div className="mob-tab-body">
      <div className="mob-h">일지 · {member.name}</div>
      <div className="mob-sub">{notes.length}건 · 녹음 {notes.reduce((s, n) => s + (n.media || []).filter(m => m.kind === 'audio').length, 0)}</div>

      {/* 선생님께 직접 문의 — 인앱 메신저 X, OS-네이티브 카톡/전화로 */}
      <div className="mob-contact">
        <div className="mob-contact__head">
          <div className="col" style={{ gap: 2, minWidth: 0 }}>
            <span className="t-body-strong" style={{ fontSize: 13 }}>선생님께 직접 문의</span>
            <span className="t-caption" style={{ fontSize: 11, lineHeight: 1.4 }}>
              일지에 대한 질문은 카톡 채널로 보내주세요. {recentTeacher?.name} 선생님이 직접 확인합니다.
            </span>
          </div>
        </div>
        <div className="mob-contact__actions">
          <button className="mob-contact__btn is-kakao" onClick={openKakao} title={`카카오톡 채널 ${Dm.settings.kakaoChannelHandle}`}>
            <span className="mob-contact__icon mob-contact__icon--kakao">K</span>
            <span className="col" style={{ gap: 0, alignItems: 'flex-start' }}>
              <span style={{ fontWeight: 600, fontSize: 12.5 }}>카카오톡 채널</span>
              <span style={{ fontSize: 10.5, color: 'var(--text-tertiary)' }}>{Dm.settings.kakaoChannelHandle}</span>
            </span>
          </button>
          <button className="mob-contact__btn" onClick={openCall} title={Dm.settings.supportPhone}>
            <span className="mob-contact__icon"><Icon.Phone size={14}/></span>
            <span className="col" style={{ gap: 0, alignItems: 'flex-start' }}>
              <span style={{ fontWeight: 600, fontSize: 12.5 }}>전화</span>
              <span style={{ fontSize: 10.5, color: 'var(--text-tertiary)' }} className="t-mono num">{Dm.settings.supportPhone}</span>
            </span>
          </button>
        </div>
      </div>

      {notes.length === 0 && <div className="mob-empty">아직 작성된 일지가 없습니다.</div>}
      {notes.map(n => (
        <div key={n.id} className="mob-card">
          <div className="row" style={{ marginBottom: 6 }}>
            <strong style={{ fontSize: 13 }}>{Dm.formatDate(n.date, { short: true })}</strong>
            <span className="t-caption" style={{ marginLeft: 'auto', fontSize: 11 }}>{Dm.getTeacher(n.teacherId)?.name} 선생님</span>
          </div>
          {(n.media || []).length > 0 && (
            <div className="mob-media">
              {n.media.map(md => md.kind === 'audio' ? (
                <div key={md.id} className="mob-audio">
                  <span style={{ fontSize: 11 }}>▶</span>
                  <span className="t-mono num" style={{ fontSize: 11, fontWeight: 600 }}>
                    {String(Math.floor(md.durationSec / 60)).padStart(2,'0')}:{String(md.durationSec % 60).padStart(2,'0')}
                  </span>
                  <span className="t-caption" style={{ fontSize: 11, color: 'var(--accent-default)' }}>{md.caption}</span>
                </div>
              ) : (
                <div key={md.id} className="mob-photo">
                  <Icon.Eye size={12}/>
                  <span className="t-caption" style={{ fontSize: 11, color: 'var(--type-rental)' }}>{md.caption}</span>
                </div>
              ))}
            </div>
          )}
          <div className="col" style={{ gap: 4 }}>
            {Object.entries(n.fields).map(([k, v]) => (
              <div key={k} style={{ fontSize: 12.5, lineHeight: 1.45 }}>
                <span style={{ color: 'var(--text-tertiary)', display: 'inline-block', width: 72 }}>{k}</span>
                <span>{v}</span>
              </div>
            ))}
          </div>
          {n.memberMessage && (
            <div className="mob-memo">
              <div className="t-micro" style={{ color: 'var(--accent-default)', marginBottom: 4 }}>선생님 한마디</div>
              {n.memberMessage}
            </div>
          )}
        </div>
      ))}
    </div>
  );
}

// — Tab: 예약 (reschedule + hold)
function MemBookTab({ member }) {
  const upcoming = Dm.reservations.filter(r => r.memberId === member.id);
  const reqs = Dm.rescheduleRequests.filter(r => r.memberId === member.id);
  const holds = Dm.holdRequests.filter(h => h.memberId === member.id);
  return (
    <div className="mob-tab-body">
      <div className="mob-h">예약</div>
      <div className="mob-sub">앞으로 {upcoming.length}회 · 변경 가능 D-1까지</div>

      {upcoming.slice(0, 4).map(r => {
        const req = reqs.find(rq => rq.lessonId === r.id);
        return (
          <div key={r.id} className="mob-card">
            <div className="row">
              <div className="col" style={{ gap: 0 }}>
                <strong style={{ fontSize: 13 }}>{Dm.dayNames[r.dow]}요일 · {Dm.formatTime(r.start)}</strong>
                <span className="t-caption" style={{ fontSize: 11 }}>
                  {Dm.getRoom(r.roomId)?.name} · {Dm.getTeacher(r.teacherId)?.name} 선생님
                </span>
              </div>
              {req
                ? <UI.Badge tone="warning" dot>변경 요청 중</UI.Badge>
                : <UI.Badge tone="success" dot>확정</UI.Badge>}
            </div>
            {!req && (
              <div className="row" style={{ marginTop: 8, gap: 6 }}>
                <UI.Button size="sm" variant="ghost" icon={Icon.Refresh}>시간 변경 요청</UI.Button>
              </div>
            )}
            {req && (
              <div className="mob-req">
                <div className="t-micro" style={{ marginBottom: 4 }}>제안한 시간 (학원장 승인 대기)</div>
                {req.proposedSlots.map((s, i) => (
                  <div key={i} className="t-mono num" style={{ fontSize: 12 }}>· {s.start}</div>
                ))}
              </div>
            )}
          </div>
        );
      })}

      <button className="mob-card mob-card--dashed">
        <Icon.Plus size={14}/>
        <span>휴원 신청</span>
      </button>

      {holds.length > 0 && (
        <div className="mob-card">
          <div className="t-micro" style={{ marginBottom: 6 }}>휴원 신청 (대기)</div>
          {holds.map(h => (
            <div key={h.id} className="col" style={{ gap: 2 }}>
              <span className="t-mono num" style={{ fontSize: 12.5 }}>{h.holdStart} → {h.expectedReturn}</span>
              <span className="t-caption" style={{ fontSize: 11 }}>사유: {h.reason}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// — Tab: 결제 (receipts, next due)
function MemPayTab({ member }) {
  const due = Dm.payments.find(p => p.memberId === member.id);
  const paid = Dm.payments.filter(p => p.memberId === member.id && p.status === 'PAID');
  return (
    <div className="mob-tab-body">
      <div className="mob-h">결제</div>
      <div className="mob-sub">{due ? `다음 결제 ${Dm.formatRelative(due.dueDate)}` : '예정된 결제 없음'}</div>

      {due && (
        <div className="mob-card mob-card--warn">
          <div className="row" style={{ marginBottom: 8 }}>
            <span className="t-micro" style={{ color: 'var(--status-warning)' }}>다음 결제</span>
            <UI.Badge tone="warning" dot>D-{due.daysUntil || 2}</UI.Badge>
          </div>
          <div className="t-mono num" style={{ fontSize: 22, fontWeight: 700 }}>{Dm.formatMoney(due.amount)}</div>
          <div className="t-caption" style={{ fontSize: 11 }}>{Dm.formatDate(due.dueDate, { short: true })} · {due.method}</div>
          <div style={{ padding: 10, background: 'var(--bg-canvas)', borderRadius: 8, marginTop: 10 }}>
            <div className="t-mono num" style={{ fontSize: 13, fontWeight: 600 }}>국민 123-4567-89012</div>
            <div style={{ fontSize: 11, color: 'var(--text-secondary)' }}>예금주: 송유이보컬발성클래스</div>
          </div>
          <UI.Button block icon={Icon.Receipt} style={{ marginTop: 10 }}>입금 완료 알림 보내기</UI.Button>
        </div>
      )}

      <div className="t-micro" style={{ marginTop: 12, marginBottom: 6 }}>최근 영수증</div>
      {paid.length === 0 && <div className="mob-empty">최근 6개월 입금 내역 없음</div>}
      {paid.map(p => (
        <div key={p.id} className="mob-card mob-card--row">
          <div className="col" style={{ gap: 0 }}>
            <span style={{ fontSize: 13, fontWeight: 600 }}>{Dm.formatMoney(p.amount)}</span>
            <span className="t-caption" style={{ fontSize: 11 }}>{Dm.fmt.timestamp(p.paidAt)} · {p.method}</span>
          </div>
          <UI.Button size="sm" variant="ghost" icon={Icon.Eye}>영수증</UI.Button>
        </div>
      ))}
    </div>
  );
}

// — Tab: 녹음/진도 (F10 link, voice range, song progress)
function MemRecordTab({ member }) {
  const songs = Dm.songs || [];
  const inProgress = songs.filter(s => s.status === 'in-progress');
  const mastered   = songs.filter(s => s.status === 'mastered');
  const history    = (Dm.rangeHistory && Dm.rangeHistory[member.id]) || null;

  return (
    <div className="mob-tab-body">
      <div className="mob-h">녹음 · 진도</div>
      <div className="mob-sub">{songs.length}곡 · 도전중 {inProgress.length} · 마스터 {mastered.length}</div>

      <div className="mob-card">
        <div className="t-micro" style={{ marginBottom: 4 }}>음역대 추이</div>
        <div className="t-mono num" style={{ fontSize: 22, fontWeight: 700 }}>{member.range || 'C3—D5'}</div>
        <div className="t-caption" style={{ fontSize: 11, color: 'var(--status-success)' }}>▲ +2반음 (3개월)</div>
        {history && (
          <div className="mob-range-chart">
            {history.map((h, i) => (
              <div key={i} className="mob-range-chart__pt">
                <div className="t-mono" style={{ fontSize: 9, color: 'var(--text-tertiary)' }}>{h.date.slice(5)}</div>
                <div className="mob-range-chart__bar"><span style={{ height: `${50 + i * 12}%` }}/></div>
                <div className="t-mono" style={{ fontSize: 9, color: 'var(--text-primary)' }}>{h.high}</div>
              </div>
            ))}
          </div>
        )}
      </div>

      <div className="t-micro" style={{ marginTop: 12, marginBottom: 6 }}>도전중 · {inProgress.length}곡</div>
      {inProgress.map(s => (
        <div key={s.id} className="mob-card">
          <div className="row">
            <div className="col" style={{ gap: 0 }}>
              <strong style={{ fontSize: 13 }}>"{s.title}"</strong>
              <span className="t-caption" style={{ fontSize: 11 }}>{s.artist} · 원곡 {s.origKey} → 내 키 {s.myKey}</span>
            </div>
            <UI.Badge tone="warning" dot>도전중</UI.Badge>
          </div>
          <div className="mob-media" style={{ marginTop: 8 }}>
            <div className="mob-audio"><span>▶</span><span className="t-mono num" style={{ fontSize: 11 }}>11/19 · 0:48</span></div>
            <div className="mob-audio is-old"><span>▶</span><span className="t-mono num" style={{ fontSize: 11 }}>11/13 · 1:12</span></div>
          </div>
        </div>
      ))}

      <div className="t-micro" style={{ marginTop: 12, marginBottom: 6 }}>마스터 · {mastered.length}곡</div>
      {mastered.map(s => (
        <div key={s.id} className="mob-card mob-card--row">
          <div className="col" style={{ gap: 0 }}>
            <span style={{ fontSize: 13, fontWeight: 600 }}>"{s.title}"</span>
            <span className="t-caption" style={{ fontSize: 11 }}>{s.artist}</span>
          </div>
          <UI.Badge tone="success" dot>마스터</UI.Badge>
        </div>
      ))}

      <button className="mob-card mob-card--dashed">
        <Icon.Plus size={14}/>
        <span>셀프 연습 녹음 업로드</span>
      </button>
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// I5 · PARENT HOME — 3 tabs
// ────────────────────────────────────────────────────────────
function ParentHome({ guardian, onLock, onSwitchRole }) {
  const [tab, setTab] = useState('children');
  if (!guardian) return <div style={{ padding: 24 }} className="t-caption">학부모 데이터 없음</div>;
  const children = Dm.guardianMembers(guardian.id);
  return (
    <div className="mob-shell">
      <div className="mob-shell__body">
        <div className="mob-shell__ctx">
          <Icon.Layers size={12}/>
          <span><strong style={{ color: 'var(--text-primary)' }}>{guardian.name}</strong> 학부모 페이지 · 자녀 {children.length}명</span>
          <button onClick={onSwitchRole} className="mob-shell__role">회원 뷰 →</button>
          <button onClick={onLock} className="mob-shell__lock">잠금</button>
        </div>
        {tab === 'children' && <ParChildrenTab guardian={guardian} children={children}/>}
        {tab === 'notif'    && <ParNotifTab guardian={guardian}/>}
        {tab === 'pay'      && <ParPayTab guardian={guardian} children={children}/>}
      </div>
      <nav className="mob-tabs" style={{ gridTemplateColumns: 'repeat(3, 1fr)' }}>
        {[
          { id: 'children', label: '자녀', icon: Icon.Users },
          { id: 'notif',    label: '알림', icon: Icon.Bell },
          { id: 'pay',      label: '결제', icon: Icon.Card },
        ].map(t => (
          <button key={t.id} className={`mob-tab ${tab === t.id ? 'is-active' : ''}`} onClick={() => setTab(t.id)}>
            <t.icon size={16}/>
            <span>{t.label}</span>
          </button>
        ))}
      </nav>
    </div>
  );
}

function ParChildrenTab({ guardian, children: kids }) {
  return (
    <div className="mob-tab-body">
      <div className="mob-h">{guardian.name} 학부모님</div>
      <div className="mob-sub">자녀 {kids.length}명 등록</div>
      {kids.map((k, idx) => {
        const att = Dm.reservations.find(r => r.memberId === k.id && r.dow === 3);
        const status = att ? (Dm.attendance[att.id] || {}).status : null;
        const due = Dm.payments.find(p => p.memberId === k.id);
        return (
          <div key={k.id} className={`mob-card ${idx === 0 ? 'mob-card--accent-edge' : ''}`}>
            <div className="row" style={{ marginBottom: 8 }}>
              <UI.Avatar name={k.name} tone={k.tone} size="md"/>
              <div className="col" style={{ gap: 0, flex: 1 }}>
                <strong style={{ fontSize: 14 }}>{k.name}</strong>
                <span className="t-caption" style={{ fontSize: 11 }}>{Dm.getTeacher(k.teacherId)?.name} 선생님 · {k.passType === 'SESSION' ? `${k.total}회권` : '기간권'}</span>
              </div>
              {status === 'present' && <UI.Badge tone="success" dot>출석 {Dm.attendance[att.id].checkedInAt}</UI.Badge>}
              {status === 'scheduled' && <UI.Badge tone="neutral">예정 {Dm.formatTime(att.start)}</UI.Badge>}
              {!status && <UI.Badge tone="neutral">오늘 수업 없음</UI.Badge>}
            </div>
            <div className="mob-par-row">
              <span className="t-caption" style={{ fontSize: 11 }}>수강권</span>
              <span className="t-mono num" style={{ fontSize: 12, fontWeight: 600 }}>{k.remaining}/{k.total}</span>
            </div>
            {due && (
              <div className="mob-par-row">
                <span className="t-caption" style={{ fontSize: 11 }}>다음 결제</span>
                <span className="t-mono num" style={{ fontSize: 12, color: 'var(--status-warning)', fontWeight: 600 }}>
                  {Dm.formatRelative(due.dueDate)} · {(due.amount/10000).toFixed(0)}만
                </span>
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

// I7 — short relative time helper for announcement entries
function shortAnnTime(iso) {
  if (!iso) return '—';
  return Dm.fmt.relative(iso);
}

function ParNotifTab({ guardian }) {
  const baseNotifs = (Dm.parentNotifs || []).map(n => ({ ...n, when: shortAnnTime(n.at) }));
  // I7 — inject sent announcements into the parent notification log
  const annNotifs = (Dm.announcements || [])
    .filter(a => a.status === Dm.Enums.AnnouncementStatus.SENT)
    .map(a => ({
      id: 'ann-' + a.id,
      when: shortAnnTime(a.sentAt),
      kind: 'announcement',
      category: a.category,
      title: a.title,
      text:  a.body.slice(0, 80) + (a.body.length > 80 ? '…' : ''),
      channel: a.channel,
    }));
  const notifs = [...annNotifs, ...baseNotifs].sort((a, b) => {
    // "오늘" first, then date strings descending
    if (a.when.startsWith('오늘') && !b.when.startsWith('오늘')) return -1;
    if (!a.when.startsWith('오늘') && b.when.startsWith('오늘')) return 1;
    return 0;
  });
  const todayCount = notifs.filter(n => n.when.startsWith('오늘')).length;
  return (
    <div className="mob-tab-body">
      <div className="mob-h">알림</div>
      <div className="mob-sub">오늘 {todayCount}건 · 최근 일주일 {notifs.length}건</div>
      {notifs.map(n => {
        if (n.kind === 'announcement') {
          const cat = Dm.getAnnouncementCategory ? Dm.getAnnouncementCategory(n.category) : null;
          return (
            <div key={n.id} className="mob-card" style={{ borderLeft: '3px solid var(--accent-default)' }}>
              <div className="row" style={{ marginBottom: 4 }}>
                <UI.Badge tone="accent" dot>공지</UI.Badge>
                {cat && <span className={`ann-cat-chip ann-cat-${n.category}`} style={{ fontSize: 10, padding: '1px 6px' }}>{cat.label}</span>}
                <span className="t-mono num t-caption" style={{ fontSize: 11, marginLeft: 'auto' }}>{n.when}</span>
              </div>
              <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 2 }}>{n.title}</div>
              <div className="t-caption" style={{ fontSize: 12 }}>{n.text}</div>
            </div>
          );
        }
        const m = Dm.getMember(n.memberId);
        const tone = n.kind === 'check-in' ? 'success'
                   : n.kind === 'check-out' ? 'accent'
                   : n.kind === 'payment' ? 'warning'
                   : 'neutral';
        const label = n.kind === 'check-in' ? '등원'
                    : n.kind === 'check-out' ? '하원'
                    : n.kind === 'payment' ? '결제'
                    : n.kind === 'journal' ? '일지' : n.kind;
        return (
          <div key={n.id} className="mob-card">
            <div className="row" style={{ marginBottom: 4 }}>
              <UI.Badge tone={tone} dot>{label}</UI.Badge>
              <strong style={{ fontSize: 13, marginLeft: 4 }}>{m?.name}</strong>
              <span className="t-mono num t-caption" style={{ fontSize: 11, marginLeft: 'auto' }}>{n.when}</span>
            </div>
            <div className="t-caption" style={{ fontSize: 12 }}>{n.text}</div>
          </div>
        );
      })}

      <div className="mob-card">
        <div className="t-micro" style={{ marginBottom: 8 }}>알림 설정</div>
        <NotifRow label="등원 알림" on={guardian.notifyPrefs?.checkIn}/>
        <NotifRow label="하원 알림" on={guardian.notifyPrefs?.checkOut}/>
        <NotifRow label="결제 알림" on={guardian.notifyPrefs?.payment}/>
        <NotifRow label="일지 알림 (회원 동의 필요)" on={guardian.notifyPrefs?.journal}/>
        <div className="t-caption" style={{ fontSize: 11, marginTop: 6 }}>정숙 시간 22:00–08:00 · 알림 모음 후 다음 날 09시 발송</div>
      </div>
    </div>
  );
}

function NotifRow({ label, on }) {
  return (
    <div className="row" style={{ padding: '6px 0', borderBottom: '1px solid var(--border-default)' }}>
      <span style={{ fontSize: 13 }}>{label}</span>
      <span style={{ marginLeft: 'auto' }} className={`mob-pill ${on ? 'is-on' : ''}`}>{on ? 'ON' : 'OFF'}</span>
    </div>
  );
}

function ParPayTab({ guardian, children: kids }) {
  const dues = kids.map(k => Dm.payments.find(p => p.memberId === k.id)).filter(Boolean);
  const total = dues.reduce((s, p) => s + p.amount, 0);
  return (
    <div className="mob-tab-body">
      <div className="mob-h">결제</div>
      <div className="mob-sub">이번 달 청구 {dues.length}건 · 합계 {(total/10000).toFixed(0)}만원</div>

      {dues.map(p => {
        const m = Dm.getMember(p.memberId);
        return (
          <div key={p.id} className="mob-card">
            <div className="row" style={{ marginBottom: 6 }}>
              <strong style={{ fontSize: 13 }}>{m?.name}</strong>
              <UI.Badge tone={p.status === 'OVERDUE' ? 'danger' : 'warning'} dot>
                {p.status === 'OVERDUE' ? `D+${p.daysOverdue} 누락` : `D-${p.daysUntil}`}
              </UI.Badge>
            </div>
            <div className="t-mono num" style={{ fontSize: 18, fontWeight: 700 }}>{Dm.formatMoney(p.amount)}</div>
            <div className="t-caption" style={{ fontSize: 11, marginBottom: 8 }}>{Dm.formatDate(p.dueDate, { short: true })} · {p.method}</div>
            <UI.Button block icon={Icon.Receipt}>입금 알림 보내기</UI.Button>
          </div>
        );
      })}

      <div className="mob-card">
        <div className="t-micro" style={{ marginBottom: 8 }}>입금 계좌</div>
        <div className="t-mono num" style={{ fontSize: 14, fontWeight: 600 }}>국민 123-4567-89012</div>
        <div className="t-caption" style={{ fontSize: 11 }}>예금주: 송유이보컬발성클래스</div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// Shared mini bits
// ────────────────────────────────────────────────────────────
function MobTile({ label, value, sub, accent, warn, bar }) {
  const bg = accent ? 'var(--accent-subtle-bg)' : warn ? 'var(--status-warning-bg)' : 'var(--bg-surface)';
  const fg = accent ? 'var(--accent-default)' : warn ? 'var(--status-warning)' : 'var(--text-primary)';
  return (
    <div style={{ background: bg, border: '1px solid var(--border-default)', borderRadius: 12, padding: 12 }}>
      <div className="t-micro">{label}</div>
      <div className="row" style={{ alignItems: 'baseline', gap: 6, marginTop: 4 }}>
        <span className="t-mono num" style={{ fontSize: 20, fontWeight: 700, color: fg }}>{value}</span>
        <span style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>{sub}</span>
      </div>
      {bar != null && (
        <div style={{ height: 4, background: 'rgba(0,0,0,0.06)', borderRadius: 99, marginTop: 8, overflow: 'hidden' }}>
          <div style={{ height: '100%', width: `${bar * 100}%`, background: fg, borderRadius: 99 }}/>
        </div>
      )}
    </div>
  );
}

function MiniNotePeek({ note }) {
  return (
    <div className="col" style={{ gap: 4 }}>
      <span className="t-mono num" style={{ fontSize: 12, fontWeight: 600 }}>{Dm.formatDate(note.date, { short: true })}</span>
      {Object.entries(note.fields).slice(0, 2).map(([k, v]) => (
        <div key={k} style={{ fontSize: 12, lineHeight: 1.45 }}>
          <span style={{ color: 'var(--text-tertiary)', display: 'inline-block', width: 60 }}>{k}</span>
          <span>{v}</span>
        </div>
      ))}
    </div>
  );
}

window.Mobile = { MobileApp };
})();
