jest.mock('librechat-data-provider', () => ({
  ...jest.requireActual('librechat-data-provider'),
  extractVariableName: jest.fn(),
}));

jest.mock('@librechat/data-schemas', () => ({
  ...jest.requireActual('@librechat/data-schemas'),
  logger: {
    debug: jest.fn(),
    warn: jest.fn(),
  },
}));

const { checkWebSearchConfig } = require('./checks');
const { logger } = require('@librechat/data-schemas');
const { extractVariableName } = require('librechat-data-provider');

describe('checkWebSearchConfig', () => {
  let originalEnv;

  beforeEach(() => {
    // Clear all mocks
    jest.clearAllMocks();

    // Store original environment
    originalEnv = process.env;

    // Reset process.env
    process.env = { ...originalEnv };
  });

  afterEach(() => {
    // Restore original environment
    process.env = originalEnv;
  });

  describe('when webSearchConfig is undefined or null', () => {
    it('should return early without logging when config is undefined', () => {
      checkWebSearchConfig(undefined);

      expect(logger.debug).not.toHaveBeenCalled();
      expect(logger.warn).not.toHaveBeenCalled();
    });

    it('should return early without logging when config is null', () => {
      checkWebSearchConfig(null);

      expect(logger.debug).not.toHaveBeenCalled();
      expect(logger.warn).not.toHaveBeenCalled();
    });
  });

  describe('when config values are proper environment variable references', () => {
    it('should log debug message for each valid environment variable with value set', () => {
      const config = {
        serperApiKey: '${SERPER_API_KEY}',
        jinaApiKey: '${JINA_API_KEY}',
      };

      extractVariableName.mockReturnValueOnce('SERPER_API_KEY').mockReturnValueOnce('JINA_API_KEY');

      process.env.SERPER_API_KEY = 'test-serper-key';
      process.env.JINA_API_KEY = 'test-jina-key';

      checkWebSearchConfig(config);

      expect(extractVariableName).toHaveBeenCalledWith('${SERPER_API_KEY}');
      expect(extractVariableName).toHaveBeenCalledWith('${JINA_API_KEY}');
      expect(logger.debug).toHaveBeenCalledWith(
        'Web search serperApiKey: Using environment variable SERPER_API_KEY with value set',
      );
      expect(logger.debug).toHaveBeenCalledWith(
        'Web search jinaApiKey: Using environment variable JINA_API_KEY with value set',
      );
      expect(logger.warn).not.toHaveBeenCalled();
    });

    it('should log debug message for environment variables not set in environment', () => {
      const config = {
        cohereApiKey: '${COHERE_API_KEY}',
      };

      extractVariableName.mockReturnValue('COHERE_API_KEY');

      delete process.env.COHERE_API_KEY;

      checkWebSearchConfig(config);

      expect(logger.debug).toHaveBeenCalledWith(
        'Web search cohereApiKey: Using environment variable COHERE_API_KEY (not set in environment, user provided value)',
      );
      expect(logger.warn).not.toHaveBeenCalled();
    });
  });

  describe('when config values are actual values instead of environment variable references', () => {
    it('should warn when serperApiKey contains actual API key', () => {
      const config = {
        serperApiKey: 'sk-1234567890abcdef',
      };

      extractVariableName.mockReturnValue(null);

      checkWebSearchConfig(config);

      expect(logger.warn).toHaveBeenCalledWith(
        expect.stringContaining(
          '❗ Web search configuration error: serperApiKey contains an actual value',
        ),
      );
      expect(logger.warn).toHaveBeenCalledWith(
        expect.stringContaining('Current value: "sk-1234567..."'),
      );
      expect(logger.debug).not.toHaveBeenCalled();
    });

    it('should warn when firecrawlApiUrl contains actual URL', () => {
      const config = {
        firecrawlApiUrl: 'https://api.firecrawl.dev',
      };

      extractVariableName.mockReturnValue(null);

      checkWebSearchConfig(config);

      expect(logger.warn).toHaveBeenCalledWith(
        expect.stringContaining(
          '❗ Web search configuration error: firecrawlApiUrl contains an actual value',
        ),
      );
      expect(logger.warn).toHaveBeenCalledWith(
        expect.stringContaining('Current value: "https://ap..."'),
      );
    });

    it('should include documentation link in warning message', () => {
      const config = {
        firecrawlApiKey: 'fc-actual-key',
      };

      extractVariableName.mockReturnValue(null);

      checkWebSearchConfig(config);

      expect(logger.warn).toHaveBeenCalledWith(
        expect.stringContaining(
          'More info: https://www.librechat.ai/docs/configuration/librechat_yaml/web_search',
        ),
      );
    });
  });

  describe('when config contains mixed value types', () => {
    it('should only process string values and ignore non-string values', () => {
      const config = {
        serperApiKey: '${SERPER_API_KEY}',
        safeSearch: 1,
        scraperTimeout: 7500,
        jinaApiKey: 'actual-key',
      };

      extractVariableName.mockReturnValueOnce('SERPER_API_KEY').mockReturnValueOnce(null);

      process.env.SERPER_API_KEY = 'test-key';

      checkWebSearchConfig(config);

      expect(extractVariableName).toHaveBeenCalledTimes(2);
      expect(logger.debug).toHaveBeenCalledTimes(1);
      expect(logger.warn).toHaveBeenCalledTimes(1);
    });
  });

  describe('edge cases', () => {
    it('should handle config with no web search keys', () => {
      const config = {
        someOtherKey: 'value',
        anotherKey: '${SOME_VAR}',
      };

      checkWebSearchConfig(config);

      expect(extractVariableName).not.toHaveBeenCalled();
      expect(logger.debug).not.toHaveBeenCalled();
      expect(logger.warn).not.toHaveBeenCalled();
    });

    it('should truncate long values in warning messages', () => {
      const config = {
        serperApiKey: 'this-is-a-very-long-api-key-that-should-be-truncated-in-the-warning-message',
      };

      extractVariableName.mockReturnValue(null);

      checkWebSearchConfig(config);

      expect(logger.warn).toHaveBeenCalledWith(
        expect.stringContaining('Current value: "this-is-a-..."'),
      );
    });
  });
});
