// ===== Main App =====
function App() {
  const [authed, setAuthed] = useState(() => sessionStorage.getItem(D.STORAGE_AUTH) === '1');
  const [page, setPage] = useState('dashboard');
  const [bookings, setBookings] = useState([]);
  const [customers, setCustomers] = useState([]);
  const [menus, setMenus] = useState([]);
  const [settings, setSettings] = useState(D.DEFAULT_SETTINGS);
  const [blocks, setBlocks] = useState([]);
  const [notifications, setNotifications] = useState([]);
  const [readSet, setReadSet] = useState(() => new Set(D.loadJSON(D.STORAGE_NOTIFS_READ, [])));
  const [bookingModal, setBookingModal] = useState(null); // { booking, isNew, defaultDate, defaultTime }
  const [cloudError, setCloudError] = useState(null); // { table, message, timestamp }
  const [apiTokenMissing, setApiTokenMissing] = useState(() => {
    try { return !localStorage.getItem('seitai_api_token_v1'); } catch (e) { return false; }
  });
  const [moreSheet, setMoreSheet] = useState(false); // モバイル下部ナビ「もっと」シート
  const customerAddHandlerRef = useRef(null); // 顧客ページが「新規顧客追加」ハンドラを登録する場所（FAB から呼ぶ）
  // クラウド同期失敗のトースト通知
  useEffect(() => {
    const handler = (e) => {
      setCloudError({ ...e.detail, timestamp: Date.now() });
      // 5秒後に自動消去
      setTimeout(() => setCloudError(prev => (prev && Date.now() - prev.timestamp >= 5000) ? null : prev), 5500);
    };
    window.addEventListener('physio:cloud-error', handler);
    return () => window.removeEventListener('physio:cloud-error', handler);
  }, []);

  // Initial load: クラウドbootstrap完了を待ってからキャッシュからReact stateへ反映
  useEffect(() => {
    let mounted = true;
    const init = async () => {
      const S = window.Storage;
      if (S && typeof S._bootstrap === 'function') {
        try { await S._bootstrap(); } catch (e) {}
      }
      if (!mounted) return;
      D.ensureSeed();
      setBookings(D.loadJSON(D.STORAGE_KEY, []));
      setCustomers(D.loadJSON(D.STORAGE_CUSTOMERS, []));
      setMenus(D.loadJSON(D.STORAGE_MENUS, D.DEFAULT_MENUS));
      setSettings(D.loadJSON(D.STORAGE_SETTINGS, D.DEFAULT_SETTINGS));
      setBlocks(D.loadJSON(D.STORAGE_BLOCKS, []));
      setNotifications(D.loadJSON(D.STORAGE_NOTIFS, []));
    };
    init();
    return () => { mounted = false; };
  }, []);

  // Persist on change
  useEffect(() => { D.saveJSON(D.STORAGE_KEY, bookings); }, [bookings]);
  useEffect(() => { D.saveJSON(D.STORAGE_CUSTOMERS, customers); }, [customers]);
  useEffect(() => { D.saveJSON(D.STORAGE_MENUS, menus); }, [menus]);
  useEffect(() => { D.saveJSON(D.STORAGE_SETTINGS, settings); }, [settings]);
  useEffect(() => { D.saveJSON(D.STORAGE_BLOCKS, blocks); }, [blocks]);
  useEffect(() => { D.saveJSON(D.STORAGE_NOTIFS, notifications); }, [notifications]);
  useEffect(() => { D.saveJSON(D.STORAGE_NOTIFS_READ, [...readSet]); }, [readSet]);

  // Listen to LP postings (cross-tab)
  useEffect(() => {
    const onStorage = (e) => {
      if (e.key === D.STORAGE_KEY) setBookings(D.loadJSON(D.STORAGE_KEY, []));
    };
    window.addEventListener('storage', onStorage);
    return () => window.removeEventListener('storage', onStorage);
  }, []);

  // AI相談ログの未読数（Hooks Rules遵守のため early return より前に置く）
  const [aiUnread, setAiUnread] = useState(0);
  // AI相談ログから「会話を見る」で開かれたID
  const [pendingAiId, setPendingAiId] = useState(null);
  useEffect(() => {
    const onOpenAi = (e) => {
      const id = e.detail?.id;
      if (!id) return;
      setPage('aiconsults');
      setPendingAiId(id);
    };
    window.addEventListener('open-ai-consult', onOpenAi);
    return () => window.removeEventListener('open-ai-consult', onOpenAi);
  }, []);
  useEffect(() => {
    const calcAiUnread = () => {
      try {
        const logs = (typeof Storage !== 'undefined' ? Storage.sync.get('seitai_ai_logs_v1', []) : JSON.parse(localStorage.getItem('seitai_ai_logs_v1') || '[]'));
        const read = new Set((typeof Storage !== 'undefined' ? Storage.sync.get('seitai_ai_logs_read_v1', []) : JSON.parse(localStorage.getItem('seitai_ai_logs_read_v1') || '[]')));
        setAiUnread(logs.filter(l => !read.has(l.id)).length);
      } catch(e) { setAiUnread(0); }
    };
    calcAiUnread();
    // イベント駆動：localStorage変更（別タブ）/ ページ表示時 / カスタムイベントで再計算
    // （旧：3秒ポーリング → CPU負荷削減）
    const onStorage = (e) => {
      if (e.key === 'seitai_ai_logs_v1' || e.key === 'seitai_ai_logs_read_v1') calcAiUnread();
    };
    const onVisibilityChange = () => { if (!document.hidden) calcAiUnread(); };
    const onAiUpdate = () => calcAiUnread();
    window.addEventListener('storage', onStorage);
    document.addEventListener('visibilitychange', onVisibilityChange);
    window.addEventListener('ai-unread-update', onAiUpdate);
    return () => {
      window.removeEventListener('storage', onStorage);
      document.removeEventListener('visibilitychange', onVisibilityChange);
      window.removeEventListener('ai-unread-update', onAiUpdate);
    };
  }, [page]);

  const onLogin = (user) => { sessionStorage.setItem(D.STORAGE_AUTH, '1'); setAuthed(true); };
  const onLogout = () => { sessionStorage.removeItem(D.STORAGE_AUTH); setAuthed(false); };

  const openBooking = (b) => setBookingModal({ booking: b, isNew: false });
  const addBooking = (date, time) => setBookingModal({ booking: null, isNew: true, defaultDate: date, defaultTime: time });
  // 予約モーダルから顧客カルテへ遷移
  const openCustomerFromBooking = (customerId) => {
    setBookingModal(null);
    setPage('customers');
    // 顧客リスト画面で該当顧客の詳細を開くフラグをセット
    setTimeout(() => {
      window.dispatchEvent(new CustomEvent('physio:open-customer', { detail: { customerId }}));
    }, 50);
  };
  const addBookingForCustomer = (customer) => setBookingModal({
    booking: null,
    isNew: true,
    defaultDate: D.isoDate(new Date()),
    defaultTime: '10:00',
    prefilledCustomer: customer,
  });
  // 来院済の予約から「次回予約を取る」（顧客＋メニュー＋時間帯をプリフィル）
  // 注：BookingModal の useState 初期化は mount 時のみのため、いったん unmount してから新規マウントさせる
  const cloneBookingForNext = (snapshot) => {
    setBookingModal(null);
    setTimeout(() => {
      setBookingModal({
        booking: null,
        isNew: true,
        defaultDate: D.isoDate(new Date()),
        defaultTime: snapshot.time || '10:00',  // 前回と同じ時間帯（毎回同じ時間に来るお客様が多いため）
        prefilledCustomer: snapshot,
        prefilledMenu: snapshot,
      });
    }, 0);
  };
  const saveBooking = (b) => {
    // 夫婦・グループ施術モード：?force=1 で衝突チェックをバイパス
    if (b.allowConflict) {
      window.__PHYSIO_FORCE_BOOKING_IDS = window.__PHYSIO_FORCE_BOOKING_IDS || new Set();
      window.__PHYSIO_FORCE_BOOKING_IDS.add(b.id);
      // フラグはDBに保存しない（UI専用）
      const cleaned = { ...b };
      delete cleaned.allowConflict;
      b = cleaned;
    }
    // 🎫 チケット使用：保存時はカウントしない（紐付けのみ）
    // → 来店済（status='done'）に変えた時に worker側で自動 +1（maybeBumpCustomerOnDone）
    // → 「保存→確定」段階ではまだ消化扱いにしない（直感的）
    setBookings(prev => {
      const exists = prev.some(x => x.id === b.id);
      return exists ? prev.map(x => x.id === b.id ? b : x) : [...prev, b];
    });
    setBookingModal(null);
  };
  const deleteBooking = (id) => {
    if (!confirm('この予約を削除しますか？')) return;
    setBookings(prev => prev.filter(b => b.id !== id));
    setBookingModal(null);
  };
  const updateBooking = (id, patch) => {
    setBookings(prev => prev.map(b => b.id === id ? { ...b, ...patch } : b));
  };
  const markRead = (id) => setReadSet(prev => { const n = new Set(prev); n.add(id); return n; });
  const markAllRead = () => setReadSet(new Set(notifications.map(n => n.id)));

  if (!authed) return <LoginScreen onLogin={onLogin}/>;

  const unreadCount = notifications.filter(n => !readSet.has(n.id)).length;
  const todayCount = bookings.filter(b => b.date === D.isoDate(new Date()) && b.status !== 'cancelled').length;

  const NAV = [
    { id: 'dashboard', label: 'ダッシュボード', icon: 'dashboard' },
    { id: 'calendar',  label: 'カレンダー',     icon: 'calendar' },
    { id: 'bookings',  label: '予約一覧',       icon: 'list', badge: todayCount > 0 ? todayCount : null },
    { id: 'customers', label: '顧客リスト',     icon: 'users' },
    { id: 'analytics', label: '経営分析',       icon: 'star' },
    { id: 'aiconsults', label: 'AI相談ログ',    icon: 'messages', badge: aiUnread > 0 ? aiUnread : null },
    { id: 'menus',     label: 'メニュー設定',   icon: 'menu' },
    { id: 'store',     label: '店舗設定',       icon: 'store' },
    // 「通知」メニューは廃止（GCal通知＋予約一覧バッジでカバー）
  ];

  const titles = {
    dashboard: { title: 'ダッシュボード', sub: '本日の状況をひと目で把握' },
    calendar:  { title: '予約カレンダー', sub: '予約の管理と定休日設定をまとめて' },
    bookings:  { title: '予約一覧', sub: '全ての予約を検索・フィルタ' },
    customers: { title: '顧客リスト', sub: '来院履歴とカルテを一元管理' },
    analytics: { title: '経営分析', sub: '売上・LTV・CPA・顧客分析' },
    aiconsults:{ title: 'AI相談ログ', sub: 'AI院長と話されたユーザーの相談内容と分析' },
    menus:     { title: 'メニュー設定', sub: 'コース・料金の管理' },
    store:     { title: '店舗設定', sub: '営業時間・スタッフ・通知' },
    notifs:    { title: '通知', sub: '新規予約・キャンセル履歴' }
  };
  const t = titles[page] || titles.dashboard;

  return (
    <div className="app">
      {apiTokenMissing && (
        <div style={{
          position:'sticky', top:0, zIndex:9998,
          background:'#fdf0d6', borderBottom:'2px solid #d6651e', color:'#8a4a10',
          padding:'10px 16px', display:'flex', alignItems:'center', gap:10, flexWrap:'wrap',
          fontSize:13.5, lineHeight:1.4
        }}>
          <span style={{fontSize:16}}>🔐</span>
          <span style={{flex:1, fontWeight:600, minWidth:200}}>
            APIトークンが未設定です。データを取得できません。
          </span>
          <button
            className="btn primary"
            style={{padding:'6px 14px', fontSize:13}}
            onClick={() => {
              const cur = (() => { try { return localStorage.getItem('seitai_api_token_v1') || ''; } catch (e) { return ''; }})();
              const t = window.prompt('APIトークンを入力してください（エンジニアから受け取った文字列）:', cur);
              if (t && t.trim()) {
                try { localStorage.setItem('seitai_api_token_v1', t.trim()); } catch (e) {}
                location.reload();
              }
            }}
          >
            トークンを入力
          </button>
        </div>
      )}
      {cloudError && (
        <div style={{
          position:'fixed', top:16, right:16, zIndex:9999,
          background:'#fee2e2', border:'1px solid #fecaca', color:'#991b1b',
          padding:'12px 16px', borderRadius:8, boxShadow:'0 6px 24px rgba(0,0,0,0.15)',
          fontSize:13, maxWidth:360, lineHeight:1.5
        }}>
          <div style={{fontWeight:700, marginBottom:4}}>⚠ クラウド同期エラー</div>
          <div style={{fontSize:12, color:'#7c2222'}}>
            {cloudError.table}: {cloudError.message}
          </div>
          <div style={{fontSize:11, marginTop:6, color:'#9a3232'}}>
            データは画面上に表示されていますが、クラウドへの保存に失敗しました。ネット接続を確認してください。
          </div>
          <button onClick={() => setCloudError(null)} style={{
            position:'absolute', top:6, right:8, background:'transparent', border:0,
            fontSize:16, cursor:'pointer', color:'#7c2222'
          }}>×</button>
        </div>
      )}
      <aside className="sidebar">
        <div className="sb-brand">
          <div className="sb-brand-mark">整</div>
          <div className="sb-brand-text">
            <div className="ja">{settings.storeName}</div>
            <div className="en">ADMIN</div>
          </div>
        </div>
        <div className="sb-section-label">MAIN</div>
        <div className="sb-nav">
          {NAV.slice(0, 5).map(n => (
            <button key={n.id} className={'sb-item' + (page === n.id ? ' active' : '')} onClick={() => setPage(n.id)}>
              <span className="icon"><Icon name={n.icon} size={18}/></span>
              <span>{n.label}</span>
              {n.badge && <span className="badge">{n.badge}</span>}
            </button>
          ))}
        </div>
        <div className="sb-section-label">SETTINGS</div>
        <div className="sb-nav">
          {NAV.slice(5).map(n => (
            <button key={n.id} className={'sb-item' + (page === n.id ? ' active' : '')} onClick={() => setPage(n.id)}>
              <span className="icon"><Icon name={n.icon} size={18}/></span>
              <span>{n.label}</span>
              {n.badge && <span className="badge">{n.badge}</span>}
            </button>
          ))}
        </div>
        <div className="sb-spacer"/>
        <div className="sb-user">
          <div className="sb-user-avatar">院</div>
          <div className="sb-user-info">
            <div className="name">院長</div>
            <div className="role">オーナー</div>
          </div>
          <button className="sb-logout" onClick={onLogout} title="ログアウト"><Icon name="logout" size={16}/></button>
        </div>
      </aside>

      <main className="main">
        <header className="topbar">
          <div>
            <h1 className="topbar-title">{t.title}</h1>
            <div className="topbar-sub">{t.sub}</div>
          </div>
          <div className="topbar-spacer"/>
          {/* 通知ベルは廃止（GCal通知＋予約一覧バッジでカバー） */}
          {page !== 'calendar' && (
            <button className="topbar-action" onClick={() => addBooking(D.isoDate(new Date()), '10:00')}>
              <Icon name="plus" size={14}/> 予約を追加
            </button>
          )}
        </header>

        <div className="content">
          {page === 'dashboard' && <Dashboard bookings={bookings} customers={customers} menus={menus} settings={settings} onOpenBooking={openBooking} onNavigate={setPage}/>}
          {page === 'calendar'  && <CalendarPage bookings={bookings} settings={settings} blocks={blocks} onSetBlocks={setBlocks} menus={menus} customers={customers} onOpenBooking={openBooking} onAddBooking={addBooking} onUpdateBooking={updateBooking}/>}
          {page === 'bookings'  && <BookingsPage bookings={bookings} onOpenBooking={openBooking} onAddBooking={addBooking}/>}
          {page === 'customers' && <CustomersPage customers={customers} bookings={bookings} settings={settings} onSetCustomers={setCustomers} onAddBookingFor={addBookingForCustomer} addHandlerRef={customerAddHandlerRef}/>}
          {page === 'analytics' && <AnalyticsPage bookings={bookings} customers={customers} settings={settings} blocks={blocks} onSetSettings={setSettings}/>}
          {page === 'menus'     && <MenusPage menus={menus} onSetMenus={setMenus}/>}
          {page === 'store'     && <StorePage settings={settings} onSetSettings={setSettings} customers={customers} onSetCustomers={setCustomers}/>}
          {page === 'aiconsults' && <AIConsultsPage pendingSelectId={pendingAiId} onConsumePending={() => setPendingAiId(null)} bookings={bookings} onOpenBooking={openBooking}/>}
        </div>
      </main>

      {/* Mobile FAB: ページに応じて動作を切替（≤600px のみ表示／CSS で制御） */}
      <button
        className="fab-add"
        onClick={() => {
          if (page === 'customers' && customerAddHandlerRef.current) {
            customerAddHandlerRef.current();
          } else {
            addBooking(D.isoDate(new Date()), '10:00');
          }
        }}
        aria-label={page === 'customers' ? '顧客を追加' : '予約を追加'}
        title={page === 'customers' ? '顧客を追加' : '予約を追加'}
      >
        <Icon name="plus" size={26}/>
      </button>

      {/* Mobile bottom nav (≤600px のみ表示／CSS で制御) */}
      <nav className="mobile-nav">
        {[
          { id: 'dashboard', label: 'ホーム',     icon: 'dashboard' },
          { id: 'calendar',  label: 'カレンダー', icon: 'calendar' },
          { id: 'bookings',  label: '予約',       icon: 'list',  badge: todayCount > 0 ? todayCount : null },
          { id: 'customers', label: '顧客',       icon: 'users' },
          { id: '__more',    label: 'もっと',     icon: 'menu',  badge: aiUnread > 0 ? aiUnread : null },
        ].map(n => (
          <button
            key={n.id}
            className={'mn-item' + (page === n.id ? ' active' : '')}
            onClick={() => n.id === '__more' ? setMoreSheet(true) : setPage(n.id)}
          >
            <span className="mn-icon"><Icon name={n.icon} size={22}/></span>
            <span className="mn-label">{n.label}</span>
            {n.badge && <span className="mn-badge">{n.badge}</span>}
          </button>
        ))}
      </nav>

      {/* Mobile more sheet（スライドアップ） */}
      {moreSheet && (
        <div className="more-sheet-backdrop" onClick={() => setMoreSheet(false)}>
          <div className="more-sheet" onClick={e => e.stopPropagation()}>
            <div className="more-sheet-handle"/>
            <div className="more-sheet-title">メニュー</div>
            {[
              { id: 'analytics',  label: '経営分析',     icon: 'star' },
              { id: 'aiconsults', label: 'AI相談ログ',   icon: 'messages', badge: aiUnread > 0 ? aiUnread : null },
              { id: 'menus',      label: 'メニュー設定', icon: 'menu' },
              { id: 'store',      label: '店舗設定',     icon: 'store' },
            ].map(n => (
              <button
                key={n.id}
                className={'more-item' + (page === n.id ? ' active' : '')}
                onClick={() => { setPage(n.id); setMoreSheet(false); }}
              >
                <span className="more-icon"><Icon name={n.icon} size={20}/></span>
                <span className="more-label">{n.label}</span>
                {n.badge && <span className="more-badge">{n.badge}</span>}
              </button>
            ))}
            <div className="more-divider"/>
            <button
              className="more-item more-logout"
              onClick={() => { setMoreSheet(false); onLogout(); }}
            >
              <span className="more-icon"><Icon name="logout" size={20}/></span>
              <span className="more-label">ログアウト</span>
            </button>
          </div>
        </div>
      )}

      {bookingModal && (
        <BookingModal
          booking={bookingModal.booking}
          isNew={bookingModal.isNew}
          defaultDate={bookingModal.defaultDate}
          defaultTime={bookingModal.defaultTime}
          prefilledCustomer={bookingModal.prefilledCustomer}
          prefilledMenu={bookingModal.prefilledMenu}
          customers={customers}
          menus={menus}
          settings={settings}
          onClose={() => setBookingModal(null)}
          onSave={saveBooking}
          onOpenCustomer={openCustomerFromBooking}
          onDelete={deleteBooking}
          onCloneForNext={cloneBookingForNext}
        />
      )}
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
