// Session/auth helpers: resolve the current user from the cookie, write audit rows.
const R = require('./repos');
const A = require('./auth');
const { parseCookies, now } = require('./lib');

function audit(entry) {
  R.audit.add(entry);
}

// Resolve the session token from a request, supporting every client transport:
//   - `Authorization: Bearer <token>`  → native desktop/mobile apps (HTTP + WS upgrade)
//   - `sid` cookie                     → the web app (HTTP + same-origin WS)
//   - `?access_token=`/`?token=` query → browser WS fallback when a cookie isn't usable
// All three resolve to the same opaque token in `sessions_auth`.
function tokenFromReq(req) {
  const h = req.headers && (req.headers.authorization || req.headers.Authorization);
  if (h && /^Bearer\s+/i.test(h)) return h.replace(/^Bearer\s+/i, '').trim();
  const cookieTok = parseCookies(req).sid;
  if (cookieTok) return cookieTok;
  try {
    const qs = (req.url || '').split('?')[1];
    if (qs) { const t = new URLSearchParams(qs).get('access_token') || new URLSearchParams(qs).get('token'); if (t) return t; }
  } catch (_) {}
  return null;
}

// Resolve the logged-in user from the request. Returns user row (with mfa state) or null.
// Async: the repos it reads go through the DB adapter, so every caller must `await currentUser(...)`.
async function currentUser(req, { requireMfa = true } = {}) {
  const tok = tokenFromReq(req);
  if (!tok) return null;
  const s = await R.authSessions.byToken(tok);
  if (!s || s.expires_at < now()) return null;
  if (requireMfa && !s.mfa_passed) return null;
  const u = await R.users.byId(s.user_id);
  if (!u || u.active === 0) return null;
  return { ...u, _session: s };
}

// Resolve a third-party API key from `X-API-Key` or `Authorization: Bearer bzc_...`.
// Returns { id, teamId, scopes:[], name } or null. Keys are prefixed `bzc_` and stored hashed.
async function apiKeyFromReq(req) {
  let raw = req.headers && req.headers['x-api-key'];
  if (!raw) {
    const h = req.headers && (req.headers.authorization || req.headers.Authorization);
    if (h && /^Bearer\s+bzc_/i.test(h)) raw = h.replace(/^Bearer\s+/i, '').trim();
  }
  if (!raw || !/^bzc_/.test(raw)) return null;
  const row = await R.apiKeys.byHash(A.hashToken(raw));
  if (!row || row.revoked) return null;
  return { id: row.id, teamId: row.team_id, scopes: String(row.scopes || '').split(',').map((s) => s.trim()).filter(Boolean), name: row.name };
}
function keyHasScope(key, scope) { return !!key && (key.scopes.includes(scope) || key.scopes.includes('*')); }

module.exports = { audit, currentUser, tokenFromReq, apiKeyFromReq, keyHasScope };
