// Admin-DB-Übersicht — lesend; API erfordert X-Admin-DB-Token (ADMIN_DB_TOKEN im Backend).
function getApiBase() {
  if (typeof window !== 'undefined' && window.__CINEV_API_BASE__) {
    return String(window.__CINEV_API_BASE__).replace(/\/$/, '');
  }
  if (typeof window !== 'undefined' && window.location && window.location.port === '3040') {
    return '';
  }
  return 'http://localhost:3040';
}

const ADMIN_TOKEN_KEY = 'cinev_admin_db_token';

function AdminDbView() {
  useLang();
  const [token, setToken] = React.useState(() =>
    typeof sessionStorage !== 'undefined' ? sessionStorage.getItem(ADMIN_TOKEN_KEY) || '' : '',
  );
  const [tokenInput, setTokenInput] = React.useState('');
  const [tables, setTables] = React.useState([]);
  const [selected, setSelected] = React.useState(null);
  const [columns, setColumns] = React.useState([]);
  const [rows, setRows] = React.useState([]);
  const [total, setTotal] = React.useState(0);
  const [offset, setOffset] = React.useState(0);
  const [orderBy, setOrderBy] = React.useState('');
  const [orderDir, setOrderDir] = React.useState('asc');
  const [loading, setLoading] = React.useState(false);
  const [err, setErr] = React.useState('');

  const limit = 50;
  const base = getApiBase();
  const headers = () => ({
    'X-Admin-DB-Token': token,
    'Content-Type': 'application/json',
  });

  const saveToken = () => {
    const v = tokenInput.trim();
    setToken(v);
    if (typeof sessionStorage !== 'undefined') sessionStorage.setItem(ADMIN_TOKEN_KEY, v);
  };

  const loadTables = React.useCallback(async () => {
    if (!token) return;
    setLoading(true);
    setErr('');
    try {
      const r = await fetch(`${base}/api/v1/admin/db/tables`, { headers: headers() });
      const j = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(j.message || r.statusText);
      setTables(j.items || []);
    } catch (e) {
      let msg = e.message || String(e);
      if (msg === 'Failed to fetch' || /network/i.test(msg) || msg.includes('Load failed')) {
        msg =
          "API nicht erreichbar (Netzwerk). Läuft npm run api (Port 3040)? Wenn die Seite von einem anderen Port (z. B. Workshop 16_Scoping) lädt: in der Konsole window.__CINEV_API_BASE__='http://127.0.0.1:3040' setzen und neu laden.";
      }
      setErr(msg);
      setTables([]);
    } finally {
      setLoading(false);
    }
  }, [token, base]);

  React.useEffect(() => {
    loadTables();
  }, [loadTables]);

  const loadTableDetail = async (tableName, off = 0, ob, od) => {
    if (!token || !tableName) return;
    setLoading(true);
    setErr('');
    setRows([]);
    try {
      const colR = await fetch(`${base}/api/v1/admin/db/tables/${encodeURIComponent(tableName)}/columns`, {
        headers: headers(),
      });
      const colJ = await colR.json().catch(() => ({}));
      if (!colR.ok) throw new Error(colJ.message || colR.statusText);
      setColumns(colJ.items || []);

      const obUse = ob || (colJ.items && colJ.items[0] && colJ.items[0].name) || '';
      const params = new URLSearchParams({
        limit: String(limit),
        offset: String(off),
        orderBy: obUse,
        orderDir: od || orderDir || 'asc',
      });
      const rowR = await fetch(
        `${base}/api/v1/admin/db/tables/${encodeURIComponent(tableName)}/rows?${params}`,
        { headers: headers() },
      );
      const rowJ = await rowR.json().catch(() => ({}));
      if (!rowR.ok) throw new Error(rowJ.message || rowR.statusText);
      setRows(rowJ.rows || []);
      setTotal(Number(rowJ.total || 0));
      setOffset(Number(rowJ.offset || 0));
      setOrderBy(rowJ.orderCol || obUse);
      setOrderDir(od || orderDir || 'asc');
    } catch (e) {
      let msg = e.message || String(e);
      if (msg === 'Failed to fetch' || /network/i.test(msg) || msg.includes('Load failed')) {
        msg =
          'API nicht erreichbar (Netzwerk). Backend auf Port 3040 starten; bei Aufruf von anderem Port die API-URL setzen (siehe Hilfe oben).';
      }
      setErr(msg);
      setRows([]);
      setColumns([]);
    } finally {
      setLoading(false);
    }
  };

  const openTable = (name) => {
    setSelected(name);
    setOffset(0);
    setOrderDir('asc');
    setOrderBy('');
    loadTableDetail(name, 0, '', 'asc');
  };

  const exportCsv = () => {
    if (!rows.length || !columns.length) return;
    const names = columns.map((c) => c.name);
    const esc = (v) => {
      const s = v == null ? '' : String(v);
      if (/[",\n]/.test(s)) return `"${s.replace(/"/g, '""')}"`;
      return s;
    };
    const lines = [names.join(',')].concat(rows.map((row) => names.map((n) => esc(row[n])).join(',')));
    const blob = new Blob([lines.join('\n')], { type: 'text/csv;charset=utf-8' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = `${selected || 'export'}.csv`;
    a.click();
    URL.revokeObjectURL(a.href);
  };

  const colKeys = rows.length ? Object.keys(rows[0]) : columns.map((c) => c.name);

  return (
    <div style={{ padding: '20px 32px 40px', display: 'flex', flexDirection: 'column', gap: 16, minHeight: 0 }}>
      <div style={{
        background: CINEV.card, border: `1px solid ${CINEV.line}`, borderRadius: 10, padding: '14px 16px',
        display: 'flex', flexWrap: 'wrap', alignItems: 'flex-end', gap: 12,
      }}>
        <div style={{ flex: '1 1 220px' }}>
          <div style={{ fontSize: 11, color: CINEV.inkMute, marginBottom: 4 }}>{t('ad_token_label')}</div>
          <input
            type="password"
            value={tokenInput}
            onChange={(e) => setTokenInput(e.target.value)}
            placeholder={t('ad_token_placeholder')}
            style={{
              width: '100%', padding: '8px 10px', borderRadius: 6, border: `1px solid ${CINEV.line}`,
              fontFamily: 'inherit', fontSize: 13, boxSizing: 'border-box',
            }}
          />
        </div>
        <button type="button" onClick={saveToken} style={btn('primary')}>{t('ad_token_save')}</button>
        <button type="button" onClick={loadTables} style={btn('ghost')}>{t('ad_refresh')}</button>
      </div>

      <div style={{ fontSize: 12, color: CINEV.inkSoft, lineHeight: 1.5 }}>{t('ad_hint_readonly')}</div>

      {err && (
        <div style={{
          background: '#fdf2f0', border: '1px solid #e8c4c0', color: '#6b2e2e', borderRadius: 8, padding: '10px 12px',
          fontSize: 13,
        }}>{err}</div>
      )}

      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(200px, 260px) 1fr', gap: 16, flex: 1, minHeight: 360 }}>
        <div style={{
          background: CINEV.card, border: `1px solid ${CINEV.line}`, borderRadius: 10, overflow: 'auto', maxHeight: '70vh',
        }}>
          <div style={{ padding: '12px 14px', borderBottom: `1px solid ${CINEV.line}`, fontWeight: 600, fontSize: 12 }}>
            {t('ad_tables')}
          </div>
          {loading && !tables.length && (
            <div style={{ padding: 16, color: CINEV.inkMute }}>{t('ad_loading')}</div>
          )}
          {!loading && !tables.length && !err && (
            <div style={{ padding: 16, color: CINEV.inkMute }}>{t('ad_empty_tables')}</div>
          )}
          {tables.map((trow) => (
            <button
              key={trow.name}
              type="button"
              onClick={() => openTable(trow.name)}
              style={{
                display: 'block', width: '100%', textAlign: 'left', padding: '8px 14px', border: 'none',
                borderBottom: `1px solid ${CINEV.lineSoft}`, background: selected === trow.name ? CINEV.soft : 'transparent',
                cursor: 'pointer', fontFamily: 'inherit', fontSize: 13, color: selected === trow.name ? CINEV.teal : CINEV.ink,
                fontWeight: selected === trow.name ? 600 : 400,
              }}
            >
              {trow.name}
            </button>
          ))}
        </div>

        <div style={{
          background: CINEV.card, border: `1px solid ${CINEV.line}`, borderRadius: 10, overflow: 'hidden',
          display: 'flex', flexDirection: 'column', minHeight: 320,
        }}>
          {!selected && (
            <div style={{ padding: 24, color: CINEV.inkMute }}>{t('ad_pick_table')}</div>
          )}
          {selected && (
            <>
              <div style={{
                padding: '12px 16px', borderBottom: `1px solid ${CINEV.line}`, display: 'flex',
                alignItems: 'center', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap',
              }}>
                <div style={{ fontWeight: 600, fontSize: 14 }}>{selected}</div>
                <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
                  <span style={{ fontSize: 11, color: CINEV.inkMute, fontVariantNumeric: 'tabular-nums' }}>
                    {total} {t('ad_rows')}
                  </span>
                  <button type="button" onClick={exportCsv} style={btn('ghost')}>{t('ad_export_csv')}</button>
                  <button
                    type="button"
                    disabled={offset <= 0}
                    onClick={() => {
                      const n = Math.max(0, offset - limit);
                      setOffset(n);
                      loadTableDetail(selected, n, orderBy, orderDir);
                    }}
                    style={btn('ghost')}
                  >{t('ad_prev')}</button>
                  <button
                    type="button"
                    disabled={offset + limit >= total}
                    onClick={() => {
                      const n = offset + limit;
                      setOffset(n);
                      loadTableDetail(selected, n, orderBy, orderDir);
                    }}
                    style={btn('ghost')}
                  >{t('ad_next')}</button>
                </div>
              </div>
              <div style={{ overflow: 'auto', flex: 1 }}>
                <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12 }}>
                  <thead>
                    <tr style={{ background: CINEV.bg }}>
                      {colKeys.map((k) => (
                        <th key={k} style={{
                          textAlign: 'left', padding: '8px 10px', borderBottom: `1px solid ${CINEV.line}`,
                          fontWeight: 600, whiteSpace: 'nowrap', position: 'sticky', top: 0, background: CINEV.bg,
                          fontVariantNumeric: 'tabular-nums',
                        }}>
                          <button
                            type="button"
                            onClick={() => {
                              const nextDir = orderBy === k && orderDir === 'asc' ? 'desc' : 'asc';
                              setOrderBy(k);
                              setOrderDir(nextDir);
                              setOffset(0);
                              loadTableDetail(selected, 0, k, nextDir);
                            }}
                            style={{
                              border: 'none', background: 'transparent', cursor: 'pointer', font: 'inherit',
                              color: orderBy === k ? CINEV.teal : CINEV.ink, fontWeight: 600,
                            }}
                          >
                            {k}{orderBy === k ? (orderDir === 'asc' ? ' ▲' : ' ▼') : ''}
                          </button>
                        </th>
                      ))}
                    </tr>
                  </thead>
                  <tbody>
                    {rows.map((row, ri) => (
                      <tr key={ri} style={{ borderBottom: `1px solid ${CINEV.lineSoft}` }}>
                        {colKeys.map((k) => (
                          <td key={k} style={{
                            padding: '6px 10px', verticalAlign: 'top', maxWidth: 220, overflow: 'hidden',
                            textOverflow: 'ellipsis', whiteSpace: 'nowrap', fontVariantNumeric: 'tabular-nums',
                          }} title={row[k] != null ? String(row[k]) : ''}>
                            {row[k] != null ? String(row[k]) : ''}
                          </td>
                        ))}
                      </tr>
                    ))}
                  </tbody>
                </table>
                {!loading && selected && !rows.length && (
                  <div style={{ padding: 16, color: CINEV.inkMute }}>{t('ad_empty_rows')}</div>
                )}
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}
