// ─────────────────────────────────────────────
// App.jsx  (V7)
// Views: home | list | detail
//
// V7 changes vs V6:
//   - Layout endpoint: /v7/layout instead of /v6/layout
//   - Schema: tables have _oid, tNum, tCode (not table)
//   - Layout is per-table, fetched on table select
//   - No allObjects — each view fetches its own data
// ─────────────────────────────────────────────

const DEFAULT_THEME = {
  nav_bg:        '#0f2744',
  nav_color:     '#ffffff',
  primary:       '#2563eb',
  accent:        '#f59e0b',
  font:          "'Segoe UI', sans-serif",
  font_size:     14,
  border_radius: 6,
  card_bg:       '#ffffff',
  page_bg:       '#f8fafc',
  logo_text:     'DO',
  label_size:    '10px',
  label_color:   '#64748b',
};
window.__DO_THEME__ = DEFAULT_THEME;

function App() {
  const [appName,      setAppName]      = React.useState('');
  const [appDesc,      setAppDesc]      = React.useState('');
  const [theme,        setTheme]        = React.useState(DEFAULT_THEME);
  const [settings,     setSettings]     = React.useState({ save:'manual', timeout:3000 });
  const [apiKeys,      setApiKeys]      = React.useState({});
  const [tables,       setTables]       = React.useState([]);
  const [homeReady,    setHomeReady]    = React.useState(false);
  const [inactive,     setInactive]     = React.useState(false);
  const [authReady,    setAuthReady]    = React.useState(false);
  const [jwt,          setJwt]          = React.useState(null);
  const [currentUser,  setCurrentUser]  = React.useState(null);
  const [error,        setError]        = React.useState(null);

  // View routing
  const [view,         setView]         = React.useState('home');
  const [currentTable, setCurrentTable] = React.useState(null); // { tNum, tCode, name, ... }
  const [openId,       setOpenId]       = React.useState(null);

  // Per-table layout cache
  const [tableLayouts, setTableLayouts] = React.useState({});

  // Found set
  const [foundSet,     setFoundSet]     = React.useState([]);
  const [foundTotal,   setFoundTotal]   = React.useState(0);
  const [totalRecords, setTotalRecords] = React.useState(0);

  // List state preserved across detail nav
  const [listOffset,   setListOffset]   = React.useState(0);
  const [listPageSize, setListPageSize] = React.useState(25);

  // Nav panel toggles
  const [searchOpen,  setSearchOpen]  = React.useState(false);
  const [profileOpen, setProfileOpen] = React.useState(false);

  // Detail state lifted for nav bar
  const [detailRecord,  setDetailRecord]  = React.useState(null);
  const [detailSaving,  setDetailSaving]  = React.useState(false);
  const [detailSaved,   setDetailSaved]   = React.useState(false);
  const [detailDirty,   setDetailDirty]   = React.useState(false);
  const [detailLoading, setDetailLoading] = React.useState(false);
  const [detailIsNew,   setDetailIsNew]   = React.useState(false);

  const detailRef = React.useRef(null);
  const listRef   = React.useRef(null);

  // ── Fetch client IP for DO dev panels ────────
  React.useEffect(() => {
    apiFetch(`${API_BASE}/v6/myip`)
      .then(r => r.json())
      .then(d => { window.__DO_CLIENT_IP__ = d.cf || d.forwarded?.split(',')[0]?.trim() || ''; })
      .catch(() => {});
  }, []);
  React.useEffect(() => {
    const stored = localStorage.getItem(window.jwtKey());
    if (!stored) { setAuthReady(true); return; }
    fetch(`${API_BASE}/v6/auth/session`, {
      headers: { Authorization: `Bearer ${stored}` }
    })
      .then(r => r.json())
      .then(data => {
        if (data.status === 'ok') {
          setJwt(stored);
          setCurrentUser(data.user);
        } else {
          localStorage.removeItem(window.jwtKey());
        }
      })
      .catch(() => localStorage.removeItem(window.jwtKey()))
      .finally(() => setAuthReady(true));
  }, []);

  // ── Fetch home layout once authenticated ─────
  React.useEffect(() => {
    if (!jwt) return;
    apiFetch(`${API_BASE}/v7/layout?app=${APP_ID}`)
      .then(r => r.json())
      .then(data => {
        if (data.status === 'inactive') { setInactive(true); setHomeReady(true); return; }
        if (data.status !== 'ok') throw new Error(data.message);
        setAppName(data.appName || '');
        setAppDesc(data.appDesc || '');
        if (data.appName) document.title = data.appName;
        setTables(data.tables || []);
        if (data.settings) setSettings({ save:'manual', timeout:3000, ...data.settings });
        if (data.apiKeys)  setApiKeys(data.apiKeys);
        if (data.theme) {
          const merged = { ...DEFAULT_THEME, ...data.theme };
          setTheme(merged);
          window.__DO_THEME__ = merged;
          // Apply density class to body
          const dc = { XS:'do-xs', S:'do-s', M:'do-m', L:'do-l', XL:'do-xl' };
          document.body.classList.remove('do-xs','do-s','do-m','do-l','do-xl');
          document.body.classList.add(dc[merged.density || 'M'] || 'do-m');
        }
        setHomeReady(true);
      })
      .catch(err => setError(err.message));
  }, [jwt]);

  // ── Fetch per-table layout (cached) ──────────
  async function fetchTableLayout(tCode) {
    if (tableLayouts[tCode]) return tableLayouts[tCode];
    try {
      const res  = await apiFetch(`${API_BASE}/v7/layout?app=${APP_ID}&table=${tCode}`);
      const data = await res.json();
      if (data.status !== 'ok') throw new Error(data.message);
      setTableLayouts(prev => ({ ...prev, [tCode]: data }));
      return data;
    } catch(err) {
      console.error('fetchTableLayout error:', err.message);
      return null;
    }
  }

  // ── Navigation ───────────────────────────────
  const scrollTop = () => window.scrollTo({ top:0, behavior:'instant' });

  const goHome = () => { setView('home'); scrollTop(); };

  const goList = async (tableRow) => {
    const t = tableRow || currentTable;
    if (!t) return;
    setCurrentTable(t);
    await fetchTableLayout(t.tCode);
    setView('list');
    setSearchOpen(false);
    scrollTop();
  };

  const goDetail = async (id, tableRow) => {
    const t = tableRow || currentTable;
    if (!t) return;
    setCurrentTable(t);
    await fetchTableLayout(t.tCode);
    setOpenId(id);
    setView('detail');
    setSearchOpen(false);
    scrollTop();
  };

  const handleTableSelect = async (tableRow) => {
    const link = tableRow.link || 'list';
    if (link === 'detail') {
      await goDetail(null, tableRow);
    } else {
      await goList(tableRow);
    }
  };

  const handleOpen = (r_auto, set, total) => {
    setFoundSet(set || []);
    setFoundTotal(total || 0);
    goDetail(r_auto);
  };

  const handleFoundSetChange = (set, total, pageSize, offset) => {
    setFoundSet(set);
    setFoundTotal(total);
    if (pageSize !== undefined) setListPageSize(pageSize);
    if (offset   !== undefined) setListOffset(offset);
  };

  // ── Nav bar delegates ────────────────────────
  const handleNavFirst     = () => detailRef.current?.goFirst();
  const handleNavPrev      = () => detailRef.current?.goPrev()  || listRef.current?.goPrev();
  const handleNavNext      = () => detailRef.current?.goNext()  || listRef.current?.goNext();
  const handleNavLast      = () => detailRef.current?.goLast();
  const handleNavRefresh   = () => detailRef.current?.refresh() || listRef.current?.refresh();
  const handleNavNew       = () => { if (view === 'list') goDetail('new'); else detailRef.current?.newRecord(); };
  const handleNavSave      = () => detailRef.current?.save();
  const handleNavDelete    = () => detailRef.current?.deleteRecord();
  const handleNavDuplicate = () => detailRef.current?.duplicate();

  const currentPos = view === 'detail' && detailRecord && foundSet?.length > 0
    ? foundSet.indexOf(detailRecord.r_auto) : -1;
  const hasPrev = view === 'detail' ? currentPos > 0 : listOffset > 0;
  const hasNext = view === 'detail'
    ? currentPos >= 0 && currentPos < foundSet.length - 1
    : (listOffset + listPageSize) < (foundTotal || totalRecords);

  // ── Current table layout ─────────────────────
  const tableLayout = currentTable ? tableLayouts[currentTable.tCode] : null;

  // ── Early returns ────────────────────────────
  if (error) return (
    <div style={{ padding:40, color:'#991b1b', fontFamily:'sans-serif' }}>❌ {error}</div>
  );
  if (!authReady) return (
    <div style={{ padding:40, color:'#64748b', fontFamily:'sans-serif' }}>Loading…</div>
  );
  if (!jwt) return (
    <DOLogin appId={APP_ID} theme={theme}
      appName={window.APP_NAME || 'DataObjects'} onLogin={(token, user) => {
        localStorage.setItem(window.jwtKey(), token);
        setJwt(token); setCurrentUser(user);
      }} />
  );
  if (!homeReady) return (
    <div style={{ padding:40, color:'#64748b', fontFamily:'sans-serif' }}>Loading…</div>
  );
  if (inactive) return (
    <div style={{ minHeight:'100vh', display:'flex', alignItems:'center',
                  justifyContent:'center', background: theme.page_bg,
                  fontFamily: theme.font }}>
      <div style={{ textAlign:'center', maxWidth:400, padding:'40px 32px',
                    background:'#fff', borderRadius:16, border:'1px solid #e2e8f0' }}>
        <div style={{ fontSize:48, marginBottom:20 }}>🔒</div>
        <div style={{ fontSize:20, fontWeight:700, color:'#0f1923', marginBottom:10 }}>
          App Unavailable
        </div>
        <div style={{ fontSize:14, color:'#64748b', lineHeight:1.6 }}>
          This application is currently offline.<br/>
          Please contact your administrator.
        </div>
      </div>
    </div>
  );

  const fs = theme.font_size ? `${theme.font_size}px` : '14px';
  const maxW = settings.container === 'fluid' ? '100%' : 1200;

  return (
    <div>
      <DONavBar
        view={view}
        allObjects={tables.map(t => ({
          ...t,
          group: 'schema', type: 'table',
          table: t.tCode, _table: t.tNum,
          o_id: t._oid, status: '1',
        }))}
        tables={tables}
        currentTable={currentTable?.tCode || currentTable?.code || ''}
        theme={theme}
        record={detailRecord}
        foundSet={foundSet}
        foundTotal={foundTotal}
        totalRecords={totalRecords}
        offset={listOffset}
        pageSize={listPageSize}
        saveMode={settings.save}
        saving={detailSaving}
        saved={detailSaved}
        dirty={detailDirty}
        loading={detailLoading}
        isNew={detailIsNew}
        hasPrev={hasPrev}
        hasNext={hasNext}
        onHome={goHome}
        onTableSelect={tCode => {
          const t = tables.find(t => t.tCode === tCode || t.code === tCode);
          if (t) handleTableSelect(t);
        }}
        onBack={() => goList()}
        onNew={handleNavNew}
        onRefresh={handleNavRefresh}
        onSearch={() => setSearchOpen(!searchOpen)}
        onSave={handleNavSave}
        onFirst={handleNavFirst}
        onPrev={handleNavPrev}
        onNext={handleNavNext}
        onLast={handleNavLast}
        onDelete={handleNavDelete}
        onDuplicate={handleNavDuplicate}
        currentUser={currentUser}
        onLogout={() => { localStorage.removeItem(window.jwtKey()); setJwt(null); setCurrentUser(null); }}
        onProfileOpen={() => setProfileOpen(true)}
      />

      <div style={{ maxWidth: maxW, margin:'20px auto', padding:'0 20px',
                    background: theme.page_bg, fontFamily: theme.font,
                    fontSize: fs }}>

        {/* ── HOME ── */}
        {view === 'home' && (
          <DOHomePage
            tables={tables}
            theme={theme}
            appName={appName || window.APP_NAME || ''}
            appDesc={appDesc}
            onSelect={handleTableSelect}
          />
        )}

        {/* ── LIST VIEW ── */}
        {view === 'list' && currentTable && (
          <DOListView
            ref={listRef}
            tableRow={currentTable}
            layoutData={tableLayout}
            theme={theme}
            searchOpen={searchOpen}
            onSearchClose={() => setSearchOpen(false)}
            onOpen={handleOpen}
            onFoundSetChange={handleFoundSetChange}
            onTotalRecords={total => setTotalRecords(total)}
          />
        )}

        {/* ── DETAIL VIEW ── */}
        {view === 'detail' && currentTable && (
          <DODetailView
            ref={detailRef}
            tableRow={currentTable}
            layoutData={tableLayout}
            appSettings={settings}
            apiKeys={apiKeys}
            theme={theme}
            startId={openId === 'new' ? null : openId}
            isNewRecord={openId === 'new'}
            searchOpen={searchOpen}
            onSearchClose={() => setSearchOpen(false)}
            foundSet={foundSet}
            foundTotal={foundTotal}
            onFoundSetChange={handleFoundSetChange}
            onBack={() => goList()}
            onTableSelect={handleTableSelect}
            onRecordChange={setDetailRecord}
            onSavingChange={setDetailSaving}
            onSavedChange={setDetailSaved}
            onDirtyChange={setDetailDirty}
            onLoadingChange={setDetailLoading}
            onNewChange={setDetailIsNew}
          />
        )}
      </div>

      {profileOpen && typeof DOProfile !== 'undefined' && (
        <DOProfile
          user={currentUser}
          jwt={localStorage.getItem(window.jwtKey())}
          appId={APP_ID}
          onClose={() => setProfileOpen(false)}
          onUserUpdate={u => setCurrentUser(u)}
        />
      )}
    </div>
  );
}
