import '../types/express-augmentation';
import {
  NextFunction,
  Request,
  Response
} from 'express';
import { consumeSessionToken } from '../services/session-auth.service';

function readBearerToken(req: Request): string | null {
  const header = req.header('authorization');

  if (!header || !header.toLowerCase().startsWith('bearer ')) {
    return null;
  }

  const token = header.slice(7).trim();

  return token || null;
}

export async function requireAuth(req: Request, res: Response, next: NextFunction): Promise<void> {
  const token = readBearerToken(req);

  if (!token) {
    res.status(401).json({ error: 'Missing or invalid authorization token', errorCode: 'UNAUTHORIZED' });
    return;
  }

  const session = await consumeSessionToken(token);

  if (!session) {
    res.status(401).json({ error: 'Missing or invalid authorization token', errorCode: 'UNAUTHORIZED' });
    return;
  }

  req.authToken = session.token;
  req.authUserId = session.user.id;
  req.authUser = session.user;
  next();
}

export function getAuthenticatedUserId(req: Request): string {
  const userId = req.authUserId;

  if (!userId) {
    throw new Error('Authenticated user id missing after requireAuth');
  }

  return userId;
}

export function rejectSpoofedUserId(
  req: Request,
  res: Response,
  bodyUserId: unknown,
  fieldName: string
): bodyUserId is string {
  if (typeof bodyUserId !== 'string' || !bodyUserId.trim()) {
    return false;
  }

  if (bodyUserId !== req.authUserId) {
    res.status(400).json({
      error: `${fieldName} must match the authenticated user`,
      errorCode: 'USER_ID_MISMATCH'
    });

    return false;
  }

  return true;
}
