// ─────────────────────────────────────────────────────────────
// src/auth.js — /auth/* endpoints.
//
// POST /auth/login     { email }        → 200 {ok, firstName?} on success,
//                                        403 {error: "not_invited"} otherwise.
// POST /auth/logout                     → 200
// GET  /auth/me                         → 200 {email, firstName} | 401
//
// There are no one-time codes anymore — the site is invite-list-only
// and the invite list IS the authentication factor. A person who knows
// an invited email can log in as them. The site exposes only
// marketing/preview content, so this is acceptable by design. If a user
// needs to be kicked out, remove their invite AND delete their session
// rows (see OPERATIONS.md).
// ─────────────────────────────────────────────────────────────
import { Router } from 'express';
import { q } from './db.js';
import { issueSession, clearSession } from './sessions.js';
import { rateLimit } from './middleware.js';

const router = Router();

const EMAIL_RE = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;

// ─── POST /auth/login ────────────────────────────────────────
// One API call handles the whole flow. On success we set the
// session cookie AND return the user's first name so the frontend
// can greet them without a second round-trip to /auth/me.
//
// Rate limit: 30 login attempts per IP per hour. Enough to cover
// legitimate re-logins after cookie loss, low enough to deter
// scripted enumeration of the invite list.
router.post(
  '/login',
  rateLimit({
    key: (req) => `login:${req.ip}`,
    max: 30,
    windowMs: 60 * 60 * 1000,
  }),
  (req, res) => {
    const email = String(req.body?.email || '').trim().toLowerCase();

    if (!EMAIL_RE.test(email)) {
      return res.status(400).json({ error: 'invalid_email' });
    }

    const invited = q.getInvite.get(email);
    if (!invited) {
      // Honest "not invited" — we've decided enumeration is not a
      // concern for this site (invite-list-only, preview content).
      return res.status(403).json({ error: 'not_invited' });
    }

    issueSession(req, res, email);
    return res.status(200).json({
      ok: true,
      firstName: invited.first_name || null,
    });
  }
);

// ─── POST /auth/logout ───────────────────────────────────────
router.post('/logout', (req, res) => {
  clearSession(req, res);
  return res.status(200).json({ ok: true });
});

// ─── GET /auth/me ────────────────────────────────────────────
// Returns the current user's email + first name, or 401 if no
// valid session. The frontend calls this on page load to decide
// which step of the entrance shell to show.
router.get('/me', (req, res) => {
  const s = req.cookies?.fenja_session ? q.getSession.get(req.cookies.fenja_session, Date.now()) : null;
  if (!s) return res.status(401).end();

  // Look up the invite row to fetch first_name. If the invite was
  // deleted after the session was issued, first_name will be null
  // and the frontend falls back to anonymous copy.
  const invited = q.getInvite.get(s.email);
  return res.json({
    email: s.email,
    firstName: invited?.first_name || null,
  });
});

export default router;
