import crypto from 'crypto';

const SESSION_TTL_SECONDS = Number(process.env.SESSION_TTL_SECONDS ?? 60 * 60 * 12);

function getSessionSecret() {
  return process.env.SESSION_SECRET ?? 'sysadmin-chronicles-dev-session-secret';
}

function base64urlEncode(value) {
  return Buffer.from(value).toString('base64url');
}

function base64urlDecode(value) {
  return Buffer.from(value, 'base64url').toString('utf8');
}

function sign(value) {
  return crypto.createHmac('sha256', getSessionSecret()).update(value).digest('base64url');
}

export function issueSessionToken() {
  const issuedAt = Math.floor(Date.now() / 1000);
  const payload = {
    sid: crypto.randomUUID(),
    iat: issuedAt,
    exp: issuedAt + SESSION_TTL_SECONDS
  };

  const encodedPayload = base64urlEncode(JSON.stringify(payload));
  const signature = sign(encodedPayload);
  return {
    token: `${encodedPayload}.${signature}`,
    expiresAt: new Date(payload.exp * 1000).toISOString()
  };
}

export function verifySessionToken(token) {
  if (typeof token !== 'string' || !token.includes('.')) {
    return { ok: false, reason: 'invalid-token' };
  }

  const [encodedPayload, signature] = token.split('.', 2);
  const expectedSignature = sign(encodedPayload);

  if (!signature) {
    return { ok: false, reason: 'bad-signature' };
  }

  const provided = Buffer.from(signature);
  const expected = Buffer.from(expectedSignature);
  if (provided.length !== expected.length || !crypto.timingSafeEqual(provided, expected)) {
    return { ok: false, reason: 'bad-signature' };
  }

  try {
    const payload = JSON.parse(base64urlDecode(encodedPayload));
    const now = Math.floor(Date.now() / 1000);
    if (Number(payload.exp ?? 0) <= now) {
      return { ok: false, reason: 'expired' };
    }

    return {
      ok: true,
      payload
    };
  } catch {
    return { ok: false, reason: 'invalid-payload' };
  }
}

export function requireSession(req, res, next) {
  const header = req.headers.authorization ?? '';
  const match = header.match(/^Bearer\s+(.+)$/i);
  const token = match?.[1] ?? '';
  const verification = verifySessionToken(token);

  if (!verification.ok) {
    res.status(401).json({ error: 'Unauthorized' });
    return;
  }

  req.session = verification.payload;
  next();
}
