import { Request, Response, NextFunction } from 'express';
import { UserRole } from '@ehandyhire/shared';
import { verifyAccessToken } from '../lib/jwt';
import { AppError } from '../lib/utils';
import prisma from '../lib/prisma';
import { touchLastActive } from '../lib/lastActive';

export interface AuthRequest extends Request {
  user?: {
    userId: string;
    role: UserRole;
    email?: string;
  };
}

export async function authenticate(
  req: AuthRequest,
  _res: Response,
  next: NextFunction
) {
  try {
    const authHeader = req.headers.authorization;
    const token = authHeader?.startsWith('Bearer ')
      ? authHeader.slice(7)
      : req.cookies?.accessToken;

    if (!token) {
      throw new AppError('Authentication required', 401);
    }

    const payload = verifyAccessToken(token);
    const user = await prisma.user.findFirst({
      where: { id: payload.userId, status: 'ACTIVE', deletedAt: null },
    });

    if (!user) {
      throw new AppError('User not found or suspended', 401);
    }

    req.user = payload;
    void touchLastActive(payload.userId);
    next();
  } catch (error) {
    next(error);
  }
}

export function authorize(...roles: UserRole[]) {
  return (req: AuthRequest, _res: Response, next: NextFunction) => {
    if (!req.user) {
      return next(new AppError('Authentication required', 401));
    }
    if (!roles.includes(req.user.role)) {
      return next(new AppError('Insufficient permissions', 403));
    }
    next();
  };
}

export function optionalAuth(
  req: AuthRequest,
  _res: Response,
  next: NextFunction
) {
  const authHeader = req.headers.authorization;
  const token = authHeader?.startsWith('Bearer ')
    ? authHeader.slice(7)
    : req.cookies?.accessToken;

  if (token) {
    try {
      req.user = verifyAccessToken(token);
    } catch {
      // ignore invalid token for optional auth
    }
  }
  next();
}
