jest.mock('@librechat/data-schemas', () => ({
  logger: { error: jest.fn(), debug: jest.fn(), warn: jest.fn(), info: jest.fn() },
}));
jest.mock('~/server/services/GraphTokenService', () => ({
  getGraphApiToken: jest.fn(),
}));
jest.mock('~/server/services/AuthService', () => ({
  requestPasswordReset: jest.fn(),
  setOpenIDAuthTokens: jest.fn(),
  setCloudFrontAuthCookies: jest.fn(),
  resetPassword: jest.fn(),
  setAuthTokens: jest.fn(),
  registerUser: jest.fn(),
}));
jest.mock('~/strategies', () => ({ getOpenIdConfig: jest.fn(), getOpenIdEmail: jest.fn() }));
jest.mock('openid-client', () => ({ refreshTokenGrant: jest.fn() }));
jest.mock('~/models', () => ({
  deleteAllUserSessions: jest.fn(),
  getUserById: jest.fn(),
  findSession: jest.fn(),
  updateUser: jest.fn(),
  findUser: jest.fn(),
}));
jest.mock('@librechat/api', () => ({
  math: jest.fn((value, fallback) => fallback),
  isEnabled: jest.fn(),
  findOpenIDUser: jest.fn(),
  getOpenIdIssuer: jest.fn(() => 'https://issuer.example.com'),
  buildOpenIDRefreshParams: jest.fn(() => {
    const params = {};
    if (process.env.OPENID_SCOPE) {
      params.scope = process.env.OPENID_SCOPE;
    }
    if (process.env.OPENID_REFRESH_AUDIENCE) {
      params.audience = process.env.OPENID_REFRESH_AUDIENCE;
    }
    return params;
  }),
}));

const openIdClient = require('openid-client');
const jwt = require('jsonwebtoken');
const { logger } = require('@librechat/data-schemas');
const { isEnabled, findOpenIDUser, buildOpenIDRefreshParams } = require('@librechat/api');
const { graphTokenController, refreshController } = require('./AuthController');
const { getGraphApiToken } = require('~/server/services/GraphTokenService');
const {
  setOpenIDAuthTokens,
  setCloudFrontAuthCookies,
  setAuthTokens,
} = require('~/server/services/AuthService');
const { getOpenIdConfig, getOpenIdEmail } = require('~/strategies');
const { getUserById, findSession, updateUser } = require('~/models');

const ORIGINAL_OPENID_SCOPE = process.env.OPENID_SCOPE;
const ORIGINAL_OPENID_REFRESH_AUDIENCE = process.env.OPENID_REFRESH_AUDIENCE;
const ORIGINAL_JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET;
const ORIGINAL_NODE_ENV = process.env.NODE_ENV;

describe('graphTokenController', () => {
  let req, res;

  beforeEach(() => {
    jest.clearAllMocks();
    isEnabled.mockReturnValue(true);

    req = {
      user: {
        openidId: 'oid-123',
        provider: 'openid',
        federatedTokens: {
          access_token: 'federated-access-token',
          id_token: 'federated-id-token',
        },
      },
      headers: { authorization: 'Bearer app-jwt-which-is-id-token' },
      query: { scopes: 'https://graph.microsoft.com/.default' },
    };

    res = {
      status: jest.fn().mockReturnThis(),
      json: jest.fn(),
    };

    getGraphApiToken.mockResolvedValue({
      access_token: 'graph-access-token',
      token_type: 'Bearer',
      expires_in: 3600,
    });
  });

  it('should pass federatedTokens.access_token as OBO assertion, not the auth header bearer token', async () => {
    await graphTokenController(req, res);

    expect(getGraphApiToken).toHaveBeenCalledWith(
      req.user,
      'federated-access-token',
      'https://graph.microsoft.com/.default',
    );
    expect(getGraphApiToken).not.toHaveBeenCalledWith(
      expect.anything(),
      'app-jwt-which-is-id-token',
      expect.anything(),
    );
  });

  it('should return the graph token response on success', async () => {
    await graphTokenController(req, res);

    expect(res.json).toHaveBeenCalledWith({
      access_token: 'graph-access-token',
      token_type: 'Bearer',
      expires_in: 3600,
    });
  });

  it('should return 403 when user is not authenticated via Entra ID', async () => {
    req.user.provider = 'google';
    req.user.openidId = undefined;

    await graphTokenController(req, res);

    expect(res.status).toHaveBeenCalledWith(403);
    expect(getGraphApiToken).not.toHaveBeenCalled();
  });

  it('should return 403 when OPENID_REUSE_TOKENS is not enabled', async () => {
    isEnabled.mockReturnValue(false);

    await graphTokenController(req, res);

    expect(res.status).toHaveBeenCalledWith(403);
    expect(getGraphApiToken).not.toHaveBeenCalled();
  });

  it('should return 400 when scopes query param is missing', async () => {
    req.query.scopes = undefined;

    await graphTokenController(req, res);

    expect(res.status).toHaveBeenCalledWith(400);
    expect(getGraphApiToken).not.toHaveBeenCalled();
  });

  it('should return 401 when federatedTokens.access_token is missing', async () => {
    req.user.federatedTokens = {};

    await graphTokenController(req, res);

    expect(res.status).toHaveBeenCalledWith(401);
    expect(getGraphApiToken).not.toHaveBeenCalled();
  });

  it('should return 401 when federatedTokens is absent entirely', async () => {
    req.user.federatedTokens = undefined;

    await graphTokenController(req, res);

    expect(res.status).toHaveBeenCalledWith(401);
    expect(getGraphApiToken).not.toHaveBeenCalled();
  });

  it('should return 500 when getGraphApiToken throws', async () => {
    getGraphApiToken.mockRejectedValue(new Error('OBO exchange failed'));

    await graphTokenController(req, res);

    expect(res.status).toHaveBeenCalledWith(500);
    expect(res.json).toHaveBeenCalledWith({
      message: 'Failed to obtain Microsoft Graph token',
    });
  });
});

describe('refreshController – OpenID path', () => {
  const mockTokenset = {
    claims: jest.fn(),
    access_token: 'new-access',
    id_token: 'new-id',
    refresh_token: 'new-refresh',
    expires_in: 3600,
  };

  const baseClaims = {
    iss: 'https://issuer.example.com',
    sub: 'oidc-sub-123',
    oid: 'oid-456',
    email: 'user@example.com',
    exp: 9999999999,
  };

  const defaultUser = {
    _id: 'user-db-id',
    email: baseClaims.email,
    openidId: baseClaims.sub,
    password: '$2b$10$hashedpassword',
    __v: 0,
    totpSecret: 'encrypted-totp-secret',
    backupCodes: ['hashed-code-1', 'hashed-code-2'],
  };

  let req, res;
  const idpSigningSecret = 'idp-signing-secret';

  const makeSessionToken = (claims = {}) =>
    jwt.sign(
      {
        sub: baseClaims.sub,
        exp: Math.floor(Date.now() / 1000) + 3600,
        ...claims,
      },
      idpSigningSecret,
    );

  const makeSignedUserId = (id = 'user-db-id', options = { expiresIn: '1h' }) =>
    jwt.sign({ id }, process.env.JWT_REFRESH_SECRET, options);

  const setOpenIDReuseCookies = (signedUserId = makeSignedUserId()) => {
    req.headers.cookie = [
      'token_provider=openid',
      'refreshToken=stored-refresh',
      `openid_user_id=${signedUserId}`,
    ].join('; ');
  };

  beforeEach(() => {
    jest.clearAllMocks();
    delete process.env.OPENID_SCOPE;
    delete process.env.OPENID_REFRESH_AUDIENCE;
    process.env.JWT_REFRESH_SECRET = 'test-refresh-secret';

    isEnabled.mockReturnValue(true);
    getOpenIdConfig.mockReturnValue({ some: 'config' });
    openIdClient.refreshTokenGrant.mockResolvedValue(mockTokenset);
    mockTokenset.claims.mockReturnValue(baseClaims);
    getOpenIdEmail.mockReturnValue(baseClaims.email);
    setOpenIDAuthTokens.mockReturnValue('new-app-token');
    setCloudFrontAuthCookies.mockReturnValue(true);
    findOpenIDUser.mockResolvedValue({ user: { ...defaultUser }, error: null, migration: false });
    getUserById.mockResolvedValue({
      _id: 'user-db-id',
      email: baseClaims.email,
      openidId: baseClaims.sub,
    });
    updateUser.mockResolvedValue({});

    req = {
      headers: { cookie: 'token_provider=openid; refreshToken=stored-refresh' },
      session: {},
    };

    res = {
      status: jest.fn().mockReturnThis(),
      send: jest.fn().mockReturnThis(),
      redirect: jest.fn(),
    };
  });

  afterAll(() => {
    if (ORIGINAL_OPENID_SCOPE === undefined) {
      delete process.env.OPENID_SCOPE;
    } else {
      process.env.OPENID_SCOPE = ORIGINAL_OPENID_SCOPE;
    }

    if (ORIGINAL_OPENID_REFRESH_AUDIENCE === undefined) {
      delete process.env.OPENID_REFRESH_AUDIENCE;
    } else {
      process.env.OPENID_REFRESH_AUDIENCE = ORIGINAL_OPENID_REFRESH_AUDIENCE;
    }

    if (ORIGINAL_JWT_REFRESH_SECRET === undefined) {
      delete process.env.JWT_REFRESH_SECRET;
    } else {
      process.env.JWT_REFRESH_SECRET = ORIGINAL_JWT_REFRESH_SECRET;
    }
  });

  /** Asserts the full OpenID refresh grant was triggered using default mock state. */
  const expectOpenIDRefreshGrant = () => {
    expect(openIdClient.refreshTokenGrant).toHaveBeenCalledWith(
      { some: 'config' },
      'stored-refresh',
      {},
    );
    expect(setOpenIDAuthTokens).toHaveBeenCalledWith(mockTokenset, req, res, {
      userId: 'user-db-id',
      existingRefreshToken: 'stored-refresh',
      tenantId: undefined,
    });
  };

  it('should call getOpenIdEmail with token claims and use result for findOpenIDUser', async () => {
    await refreshController(req, res);

    expect(buildOpenIDRefreshParams).toHaveBeenCalledTimes(1);
    expect(getOpenIdEmail).toHaveBeenCalledWith(baseClaims);
    expect(findOpenIDUser).toHaveBeenCalledWith(
      expect.objectContaining({
        email: baseClaims.email,
        openidIssuer: baseClaims.iss,
      }),
    );
    expect(res.status).toHaveBeenCalledWith(200);
  });

  it('reuses valid OpenID session tokens and refreshes CloudFront cookies', async () => {
    const reusableIdToken = makeSessionToken();
    const signedUserId = makeSignedUserId();
    setOpenIDReuseCookies(signedUserId);
    req.session = {
      openidTokens: {
        accessToken: 'session-access-token',
        idToken: reusableIdToken,
        refreshToken: 'stored-refresh',
        lastRefreshedAt: Date.now(),
      },
    };
    const user = {
      ...defaultUser,
      federatedTokens: { access_token: 'do-not-return' },
    };
    getUserById.mockResolvedValue(user);

    await refreshController(req, res);

    expect(openIdClient.refreshTokenGrant).not.toHaveBeenCalled();
    expect(setOpenIDAuthTokens).not.toHaveBeenCalled();
    expect(getUserById).toHaveBeenCalledWith(
      'user-db-id',
      '-password -__v -totpSecret -backupCodes -federatedTokens',
    );
    expect(setCloudFrontAuthCookies).toHaveBeenCalledWith(req, res, user);
    expect(res.status).toHaveBeenCalledWith(200);
    expect(res.send).toHaveBeenCalledWith({
      token: reusableIdToken,
      user: expect.objectContaining({
        _id: 'user-db-id',
        email: baseClaims.email,
        openidId: baseClaims.sub,
      }),
    });

    const sentPayload = res.send.mock.calls[0][0];
    expect(sentPayload.user).not.toHaveProperty('password');
    expect(sentPayload.user).not.toHaveProperty('totpSecret');
    expect(sentPayload.user).not.toHaveProperty('backupCodes');
    expect(sentPayload.user).not.toHaveProperty('federatedTokens');
    expect(logger.debug).toHaveBeenCalledWith(
      '[refreshController] OpenID session token reused',
      expect.objectContaining({
        token_type: 'id_token',
        cloudfront_cookies_set: true,
      }),
    );
    const debugOutput = JSON.stringify(logger.debug.mock.calls);
    expect(debugOutput).not.toContain(reusableIdToken);
    expect(debugOutput).not.toContain(signedUserId);
    expect(debugOutput).not.toContain('session-access-token');
  });

  it('falls through to full OpenID refresh when session tokens are expired', async () => {
    const expiredToken = makeSessionToken({ exp: Math.floor(Date.now() / 1000) - 60 });
    setOpenIDReuseCookies();
    req.session = {
      openidTokens: {
        accessToken: expiredToken,
        idToken: expiredToken,
        refreshToken: 'stored-refresh',
        lastRefreshedAt: Date.now(),
      },
    };

    await refreshController(req, res);

    expect(getUserById).not.toHaveBeenCalled();
    expect(setCloudFrontAuthCookies).not.toHaveBeenCalled();
    expectOpenIDRefreshGrant();
  });

  it('falls through to full OpenID refresh when session tokens are near expiry', async () => {
    const nearExpiryToken = makeSessionToken({ exp: Math.floor(Date.now() / 1000) + 5 });
    setOpenIDReuseCookies();
    req.session = {
      openidTokens: {
        accessToken: nearExpiryToken,
        idToken: nearExpiryToken,
        refreshToken: 'stored-refresh',
        lastRefreshedAt: Date.now(),
      },
    };

    await refreshController(req, res);

    expect(getUserById).not.toHaveBeenCalled();
    expectOpenIDRefreshGrant();
  });

  it('falls through to full OpenID refresh when session tokens have no exp claim', async () => {
    const tokenWithoutExp = jwt.sign({ sub: baseClaims.sub }, idpSigningSecret);
    setOpenIDReuseCookies();
    req.session = {
      openidTokens: {
        accessToken: tokenWithoutExp,
        idToken: tokenWithoutExp,
        refreshToken: 'stored-refresh',
        lastRefreshedAt: Date.now(),
      },
    };

    await refreshController(req, res);

    expect(getUserById).not.toHaveBeenCalled();
    expectOpenIDRefreshGrant();
  });

  it('falls through to full OpenID refresh when the signed reuse user cookie is invalid', async () => {
    setOpenIDReuseCookies('tampered-cookie');
    req.session = {
      openidTokens: {
        accessToken: 'session-access-token',
        idToken: makeSessionToken(),
        refreshToken: 'stored-refresh',
        lastRefreshedAt: Date.now(),
      },
    };

    await refreshController(req, res);

    expect(getUserById).not.toHaveBeenCalled();
    expectOpenIDRefreshGrant();
  });

  it('falls through to full OpenID refresh when the reuse user no longer exists', async () => {
    setOpenIDReuseCookies();
    req.session = {
      openidTokens: {
        accessToken: 'session-access-token',
        idToken: makeSessionToken(),
        refreshToken: 'stored-refresh',
        lastRefreshedAt: Date.now(),
      },
    };
    getUserById.mockResolvedValueOnce(null);

    await refreshController(req, res);

    expect(getUserById).toHaveBeenCalledWith(
      'user-db-id',
      '-password -__v -totpSecret -backupCodes -federatedTokens',
    );
    expect(setCloudFrontAuthCookies).not.toHaveBeenCalled();
    expectOpenIDRefreshGrant();
  });

  it('falls through to full OpenID refresh when session tokens are stale', async () => {
    setOpenIDReuseCookies();
    req.session = {
      openidTokens: {
        accessToken: 'session-access-token',
        idToken: makeSessionToken(),
        refreshToken: 'stored-refresh',
        lastRefreshedAt: Date.now() - 16 * 60 * 1000,
      },
    };

    await refreshController(req, res);

    expect(getUserById).not.toHaveBeenCalled();
    expectOpenIDRefreshGrant();
  });

  it('falls through to full OpenID refresh when session refresh timestamp is in the future', async () => {
    setOpenIDReuseCookies();
    req.session = {
      openidTokens: {
        accessToken: 'session-access-token',
        idToken: makeSessionToken(),
        refreshToken: 'stored-refresh',
        lastRefreshedAt: Date.now() + 60 * 1000,
      },
    };

    await refreshController(req, res);

    expect(getUserById).not.toHaveBeenCalled();
    expectOpenIDRefreshGrant();
  });

  it('falls through to full OpenID refresh for pre-upgrade sessions without lastRefreshedAt', async () => {
    setOpenIDReuseCookies();
    req.session = {
      openidTokens: {
        accessToken: 'session-access-token',
        idToken: makeSessionToken(),
        refreshToken: 'stored-refresh',
      },
    };

    await refreshController(req, res);

    expect(getUserById).not.toHaveBeenCalled();
    expectOpenIDRefreshGrant();
  });

  it('sanitizes Mongoose-style user documents on the OpenID reuse path', async () => {
    const reusableIdToken = makeSessionToken();
    setOpenIDReuseCookies();
    req.session = {
      openidTokens: {
        accessToken: 'session-access-token',
        idToken: reusableIdToken,
        refreshToken: 'stored-refresh',
        lastRefreshedAt: Date.now(),
      },
    };
    const userDocument = {
      toObject: () => ({
        ...defaultUser,
        federatedTokens: { access_token: 'do-not-return' },
      }),
    };
    getUserById.mockResolvedValue(userDocument);

    await refreshController(req, res);

    const sentPayload = res.send.mock.calls[0][0];
    expect(setCloudFrontAuthCookies).toHaveBeenCalledWith(req, res, userDocument);
    expect(sentPayload).toEqual({
      token: reusableIdToken,
      user: expect.objectContaining({
        _id: 'user-db-id',
        email: baseClaims.email,
      }),
    });
    expect(sentPayload.user).not.toHaveProperty('password');
    expect(sentPayload.user).not.toHaveProperty('federatedTokens');
  });

  it('should pass scope-only OpenID refresh params when OPENID_SCOPE is set', async () => {
    process.env.OPENID_SCOPE = 'openid profile email';

    await refreshController(req, res);

    expect(openIdClient.refreshTokenGrant).toHaveBeenCalledWith(
      { some: 'config' },
      'stored-refresh',
      { scope: 'openid profile email' },
    );
  });

  it('should pass scope and audience OpenID refresh params when both are set', async () => {
    process.env.OPENID_SCOPE = 'openid profile email';
    process.env.OPENID_REFRESH_AUDIENCE = 'https://api.example.com';

    await refreshController(req, res);

    expect(openIdClient.refreshTokenGrant).toHaveBeenCalledWith(
      { some: 'config' },
      'stored-refresh',
      {
        scope: 'openid profile email',
        audience: 'https://api.example.com',
      },
    );
  });

  it('should pass audience-only OpenID refresh params when scope is unset', async () => {
    process.env.OPENID_REFRESH_AUDIENCE = 'https://api.example.com';

    await refreshController(req, res);

    expect(openIdClient.refreshTokenGrant).toHaveBeenCalledWith(
      { some: 'config' },
      'stored-refresh',
      { audience: 'https://api.example.com' },
    );
  });

  it('should omit empty OpenID refresh audience', async () => {
    process.env.OPENID_SCOPE = 'openid profile email';
    process.env.OPENID_REFRESH_AUDIENCE = '';

    await refreshController(req, res);

    expect(openIdClient.refreshTokenGrant).toHaveBeenCalledWith(
      { some: 'config' },
      'stored-refresh',
      { scope: 'openid profile email' },
    );
  });

  it('should keep OpenID refresh diagnostics free of token and audience values', async () => {
    process.env.OPENID_SCOPE = 'openid profile email';
    process.env.OPENID_REFRESH_AUDIENCE = 'https://api.example.com';

    await refreshController(req, res);

    expect(logger.debug).toHaveBeenCalledWith('[refreshController] OpenID refresh params', {
      has_scope: true,
      has_refresh_audience: true,
    });
    expect(logger.debug).toHaveBeenCalledWith('[refreshController] OpenID refresh succeeded', {
      has_access_token: true,
      has_id_token: true,
      has_refresh_token: true,
      expires_in: 3600,
    });
    const debugOutput = JSON.stringify(logger.debug.mock.calls);
    expect(debugOutput).not.toContain('stored-refresh');
    expect(debugOutput).not.toContain('new-access');
    expect(debugOutput).not.toContain('new-id');
    expect(debugOutput).not.toContain('new-refresh');
    expect(debugOutput).not.toContain('https://api.example.com');
  });

  it('should use OPENID_EMAIL_CLAIM-resolved value when claim is present in token', async () => {
    const claimsWithUpn = { ...baseClaims, upn: 'user@corp.example.com' };
    mockTokenset.claims.mockReturnValue(claimsWithUpn);
    getOpenIdEmail.mockReturnValue('user@corp.example.com');

    const user = {
      _id: 'user-db-id',
      email: 'user@corp.example.com',
      openidId: baseClaims.sub,
    };
    findOpenIDUser.mockResolvedValue({ user, error: null, migration: false });

    await refreshController(req, res);

    expect(getOpenIdEmail).toHaveBeenCalledWith(claimsWithUpn);
    expect(findOpenIDUser).toHaveBeenCalledWith(
      expect.objectContaining({
        email: 'user@corp.example.com',
        openidIssuer: baseClaims.iss,
      }),
    );
    expect(res.status).toHaveBeenCalledWith(200);
  });

  it('should fall back to claims.email when configured claim is absent from token claims', async () => {
    getOpenIdEmail.mockReturnValue(baseClaims.email);

    await refreshController(req, res);

    expect(findOpenIDUser).toHaveBeenCalledWith(
      expect.objectContaining({
        email: baseClaims.email,
        openidIssuer: baseClaims.iss,
      }),
    );
  });

  it('should not expose sensitive fields or federatedTokens in refresh response', async () => {
    await refreshController(req, res);

    const sentPayload = res.send.mock.calls[0][0];
    expect(sentPayload).toEqual({
      token: 'new-app-token',
      user: expect.objectContaining({
        _id: 'user-db-id',
        email: baseClaims.email,
        openidId: baseClaims.sub,
      }),
    });
    expect(sentPayload.user).not.toHaveProperty('federatedTokens');
    expect(sentPayload.user).not.toHaveProperty('password');
    expect(sentPayload.user).not.toHaveProperty('totpSecret');
    expect(sentPayload.user).not.toHaveProperty('backupCodes');
    expect(sentPayload.user).not.toHaveProperty('__v');
  });

  it('should update openidId when migration is triggered on refresh', async () => {
    const user = { _id: 'user-db-id', email: baseClaims.email, openidId: null };
    findOpenIDUser.mockResolvedValue({ user, error: null, migration: true });

    await refreshController(req, res);

    expect(updateUser).toHaveBeenCalledWith(
      'user-db-id',
      expect.objectContaining({
        provider: 'openid',
        openidId: baseClaims.sub,
        openidIssuer: baseClaims.iss,
      }),
    );
    expect(res.status).toHaveBeenCalledWith(200);
  });

  it('should return 401 and redirect to /login when findOpenIDUser returns no user', async () => {
    findOpenIDUser.mockResolvedValue({ user: null, error: null, migration: false });

    await refreshController(req, res);

    expect(res.status).toHaveBeenCalledWith(401);
    expect(res.redirect).toHaveBeenCalledWith('/login');
  });

  it('should return 401 and redirect when findOpenIDUser returns an error', async () => {
    findOpenIDUser.mockResolvedValue({ user: null, error: 'AUTH_FAILED', migration: false });

    await refreshController(req, res);

    expect(res.status).toHaveBeenCalledWith(401);
    expect(res.redirect).toHaveBeenCalledWith('/login');
  });

  it('should preserve invalid OpenID refresh token behavior', async () => {
    openIdClient.refreshTokenGrant.mockRejectedValue(new Error('invalid_grant'));

    await refreshController(req, res);

    expect(res.status).toHaveBeenCalledWith(403);
    expect(res.send).toHaveBeenCalledWith('Invalid OpenID refresh token');
  });

  it('should skip OpenID path when token_provider is not openid', async () => {
    req.headers.cookie = 'token_provider=local; refreshToken=some-token';

    await refreshController(req, res);

    expect(openIdClient.refreshTokenGrant).not.toHaveBeenCalled();
  });

  it('should skip OpenID path when OPENID_REUSE_TOKENS is disabled', async () => {
    isEnabled.mockReturnValue(false);

    await refreshController(req, res);

    expect(openIdClient.refreshTokenGrant).not.toHaveBeenCalled();
  });

  it('should return 200 with token not provided when refresh token is absent', async () => {
    req.headers.cookie = 'token_provider=openid';
    req.session = {};

    await refreshController(req, res);

    expect(res.status).toHaveBeenCalledWith(200);
    expect(res.send).toHaveBeenCalledWith('Refresh token not provided');
  });
});

describe('refreshController – LibreChat path', () => {
  let req, res;
  const refreshSecret = 'test-refresh-secret';

  beforeEach(() => {
    jest.clearAllMocks();
    process.env.JWT_REFRESH_SECRET = refreshSecret;
    process.env.NODE_ENV = 'test';
    setAuthTokens.mockResolvedValue('local-app-token');
    findSession.mockResolvedValue({ expiration: new Date(Date.now() + 60_000) });

    const refreshToken = jwt.sign({ id: 'local-user-id' }, refreshSecret, {
      expiresIn: '1h',
    });
    req = {
      headers: { cookie: `refreshToken=${refreshToken}` },
      query: {},
      session: {},
    };
    res = {
      status: jest.fn().mockReturnThis(),
      send: jest.fn().mockReturnThis(),
      redirect: jest.fn(),
    };
  });

  afterAll(() => {
    if (ORIGINAL_JWT_REFRESH_SECRET === undefined) {
      delete process.env.JWT_REFRESH_SECRET;
    } else {
      process.env.JWT_REFRESH_SECRET = ORIGINAL_JWT_REFRESH_SECRET;
    }

    if (ORIGINAL_NODE_ENV === undefined) {
      delete process.env.NODE_ENV;
    } else {
      process.env.NODE_ENV = ORIGINAL_NODE_ENV;
    }
  });

  it('sanitizes user documents before returning local refresh responses', async () => {
    getUserById.mockResolvedValue({
      toObject: () => ({
        _id: 'local-user-id',
        email: 'local@example.com',
        password: 'hashed-password',
        __v: 1,
        totpSecret: 'totp-secret',
        backupCodes: ['backup-code'],
        federatedTokens: { access_token: 'do-not-return' },
      }),
    });

    await refreshController(req, res);

    const sentPayload = res.send.mock.calls[0][0];
    expect(setAuthTokens).toHaveBeenCalledWith(
      'local-user-id',
      res,
      { expiration: expect.any(Date) },
      req,
    );
    expect(sentPayload).toEqual({
      token: 'local-app-token',
      user: {
        _id: 'local-user-id',
        email: 'local@example.com',
      },
    });
  });

  it('sanitizes user documents before returning CI refresh responses', async () => {
    process.env.NODE_ENV = 'CI';
    getUserById.mockResolvedValue({
      toObject: () => ({
        _id: 'local-user-id',
        email: 'local@example.com',
        password: 'hashed-password',
        __v: 1,
        totpSecret: 'totp-secret',
        backupCodes: ['backup-code'],
        federatedTokens: { access_token: 'do-not-return' },
      }),
    });

    await refreshController(req, res);

    const sentPayload = res.send.mock.calls[0][0];
    expect(findSession).not.toHaveBeenCalled();
    expect(setAuthTokens).toHaveBeenCalledWith('local-user-id', res, null, req);
    expect(sentPayload).toEqual({
      token: 'local-app-token',
      user: {
        _id: 'local-user-id',
        email: 'local@example.com',
      },
    });
  });
});
