// src/utils/serverUtils.test.ts
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import type { Logger } from 'pino';
import { getBaseUrl } from './serverUtils';

// Create a mock logger to spy on its methods
const createMockLogger = (): Logger =>
  ({
    warn: vi.fn(),
    // Add other logger methods if they were used, but only `warn` is relevant here.
    info: vi.fn(),
    error: vi.fn(),
    debug: vi.fn(),
    fatal: vi.fn(),
    trace: vi.fn(),
    silent: vi.fn(),
    child: vi.fn(() => createMockLogger()),
    level: 'info',
  }) as unknown as Logger;

describe('serverUtils', () => {
  describe('getBaseUrl', () => {
    let mockLogger: Logger;

    // Store original env values to restore after tests
    const originalFrontendUrl = process.env.FRONTEND_URL;
    const originalBaseUrl = process.env.BASE_URL;
    const originalNodeEnv = process.env.NODE_ENV;
    const originalPort = process.env.PORT;

    beforeEach(() => {
      // Reset mocks and environment variables before each test for isolation
      vi.resetModules();
      vi.unstubAllEnvs();
      // CRITICAL: Clear env vars that might be set globally (e.g., from vitest config)
      // vi.unstubAllEnvs() only removes vars set via vi.stubEnv(), not direct assignments
      delete process.env.FRONTEND_URL;
      delete process.env.BASE_URL;
      delete process.env.NODE_ENV;
      delete process.env.PORT;
      mockLogger = createMockLogger();
    });

    afterEach(() => {
      // Restore original environment variables after each test
      vi.unstubAllEnvs();
      // Restore original values
      if (originalFrontendUrl !== undefined) process.env.FRONTEND_URL = originalFrontendUrl;
      else delete process.env.FRONTEND_URL;
      if (originalBaseUrl !== undefined) process.env.BASE_URL = originalBaseUrl;
      else delete process.env.BASE_URL;
      if (originalNodeEnv !== undefined) process.env.NODE_ENV = originalNodeEnv;
      else delete process.env.NODE_ENV;
      if (originalPort !== undefined) process.env.PORT = originalPort;
      else delete process.env.PORT;
    });

    it('should use FRONTEND_URL if it is a valid URL', () => {
      vi.stubEnv('FRONTEND_URL', 'https://valid.example.com');
      const baseUrl = getBaseUrl(mockLogger);
      expect(baseUrl).toBe('https://valid.example.com');
      expect(mockLogger.warn).not.toHaveBeenCalled();
    });

    it('should trim a trailing slash from FRONTEND_URL', () => {
      vi.stubEnv('FRONTEND_URL', 'https://valid.example.com/');
      const baseUrl = getBaseUrl(mockLogger);
      expect(baseUrl).toBe('https://valid.example.com');
    });

    it('should use BASE_URL if FRONTEND_URL is not set', () => {
      vi.stubEnv('BASE_URL', 'https://base.example.com');
      const baseUrl = getBaseUrl(mockLogger);
      expect(baseUrl).toBe('https://base.example.com');
      expect(mockLogger.warn).not.toHaveBeenCalled();
    });

    it('should fall back to localhost with default port 3000 in test environment', () => {
      vi.stubEnv('NODE_ENV', 'test');
      const baseUrl = getBaseUrl(mockLogger);
      expect(baseUrl).toBe('http://localhost:3000');
      expect(mockLogger.warn).not.toHaveBeenCalled();
    });

    it('should fall back to example.com in non-test environment', () => {
      vi.stubEnv('NODE_ENV', 'development');
      vi.stubEnv('PORT', '4000');
      const baseUrl = getBaseUrl(mockLogger);
      expect(baseUrl).toBe('http://example.com:4000');
      expect(mockLogger.warn).not.toHaveBeenCalled();
    });

    it('should log a warning and fall back to localhost if FRONTEND_URL is invalid in test env', () => {
      vi.stubEnv('NODE_ENV', 'test');
      vi.stubEnv('FRONTEND_URL', 'invalid.url.com');
      const baseUrl = getBaseUrl(mockLogger);
      expect(baseUrl).toBe('http://localhost:3000');
      expect(mockLogger.warn).toHaveBeenCalledWith(
        "[getBaseUrl] FRONTEND_URL/BASE_URL is invalid or incomplete ('invalid.url.com'). Falling back to: http://localhost:3000",
      );
    });

    it('should log a warning and fall back to example.com if FRONTEND_URL is invalid in non-test env', () => {
      vi.stubEnv('NODE_ENV', 'production');
      vi.stubEnv('FRONTEND_URL', 'invalid.url.com');
      const baseUrl = getBaseUrl(mockLogger);
      expect(baseUrl).toBe('http://example.com:3000');
      expect(mockLogger.warn).toHaveBeenCalledWith(
        "[getBaseUrl] FRONTEND_URL/BASE_URL is invalid or incomplete ('invalid.url.com'). Falling back to: http://example.com:3000",
      );
    });

    it('should throw an error if the final URL is invalid', () => {
      vi.stubEnv('FRONTEND_URL', 'http:invalid');
      expect(() => getBaseUrl(mockLogger)).toThrow(
        `[getBaseUrl] Generated URL 'http:invalid' does not match required pattern (must start with http:// or https://)`,
      );
    });
  });
});