import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { FeatureFlagService, MockFeatureFlagService, mockFeatureFlags } from './FeatureFlagService';
import * as apiBaseUrl from '../config/apiBaseUrl';

describe('FeatureFlagService', () => {
  describe('fromAPI()', () => {
    let originalBaseUrl: string | undefined;
    let fetchMock: any;

    beforeEach(() => {
      originalBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
      // Mock fetch globally
      fetchMock = vi.fn();
      global.fetch = fetchMock;
    });

    afterEach(() => {
      if (originalBaseUrl !== undefined) {
        process.env.NEXT_PUBLIC_API_BASE_URL = originalBaseUrl;
      } else {
        delete process.env.NEXT_PUBLIC_API_BASE_URL;
      }
      vi.restoreAllMocks();
    });

    it('should fetch from API and enable flags with value "enabled"', async () => {
      process.env.NEXT_PUBLIC_API_BASE_URL = 'http://api.example.com';
      
      fetchMock.mockResolvedValueOnce({
        ok: true,
        json: async () => ({
          features: {
            driver_profiles: 'enabled',
            team_profiles: 'enabled',
            wallets: 'disabled',
            sponsors: 'enabled',
            team_feature: 'disabled',
            alpha_features: 'enabled'
          }
        })
      });

      const service = await FeatureFlagService.fromAPI();

      expect(fetchMock).toHaveBeenCalledWith(
        'http://api.example.com/features',
        { next: { revalidate: 0 } }
      );
      expect(service.isEnabled('driver_profiles')).toBe(true);
      expect(service.isEnabled('team_profiles')).toBe(true);
      expect(service.isEnabled('sponsors')).toBe(true);
      expect(service.isEnabled('alpha_features')).toBe(true);
      expect(service.isEnabled('wallets')).toBe(false);
      expect(service.isEnabled('team_feature')).toBe(false);
    });

    it('should use default localhost URL when NEXT_PUBLIC_API_BASE_URL is not set', async () => {
      vi.spyOn(apiBaseUrl, 'getWebsiteApiBaseUrl').mockReturnValue('http://localhost:3001');
      
      fetchMock.mockResolvedValueOnce({
        ok: true,
        json: async () => ({
          features: {
            alpha_features: 'enabled'
          }
        })
      });

      await FeatureFlagService.fromAPI();

      expect(fetchMock).toHaveBeenCalledWith(
        'http://localhost:3001/features',
        { next: { revalidate: 0 } }
      );
    });

    it('should return empty flags on HTTP error', async () => {
      fetchMock.mockResolvedValueOnce({
        ok: false,
        status: 500,
        statusText: 'Internal Server Error'
      });

      const service = await FeatureFlagService.fromAPI();

      expect(service.isEnabled('any_flag')).toBe(false);
      expect(service.getEnabledFlags()).toEqual([]);
    });

    it('should return empty flags on network error', async () => {
      fetchMock.mockRejectedValueOnce(new Error('Network error'));

      const service = await FeatureFlagService.fromAPI();

      expect(service.isEnabled('any_flag')).toBe(false);
      expect(service.getEnabledFlags()).toEqual([]);
    });

    it('should handle empty features object', async () => {
      fetchMock.mockResolvedValueOnce({
        ok: true,
        json: async () => ({ features: {} })
      });

      const service = await FeatureFlagService.fromAPI();

      expect(service.getEnabledFlags()).toEqual([]);
    });

    it('should handle malformed response', async () => {
      fetchMock.mockResolvedValueOnce({
        ok: true,
        json: async () => ({})
      });

      const service = await FeatureFlagService.fromAPI();

      expect(service.getEnabledFlags()).toEqual([]);
    });

    it('should ignore non-"enabled" values', async () => {
      fetchMock.mockResolvedValueOnce({
        ok: true,
        json: async () => ({
          features: {
            flag1: 'enabled',
            flag2: 'disabled',
            flag3: 'pending',
            flag4: 'ENABLED', // case sensitive
            flag5: ''
          }
        })
      });

      const service = await FeatureFlagService.fromAPI();

      expect(service.isEnabled('flag1')).toBe(true);
      expect(service.isEnabled('flag2')).toBe(false);
      expect(service.isEnabled('flag3')).toBe(false);
      expect(service.isEnabled('flag4')).toBe(false);
      expect(service.isEnabled('flag5')).toBe(false);
    });
  });

  describe('Constructor behavior', () => {
    it('should use provided flags array', () => {
      const service = new FeatureFlagService(['test_flag']);
      expect(service.isEnabled('test_flag')).toBe(true);
      expect(service.isEnabled('other_flag')).toBe(false);
    });

    it('should parse FEATURE_FLAGS environment variable', () => {
      process.env.FEATURE_FLAGS = 'flag1, flag2, flag3';
      const service = new FeatureFlagService();
      
      expect(service.isEnabled('flag1')).toBe(true);
      expect(service.isEnabled('flag2')).toBe(true);
      expect(service.isEnabled('flag3')).toBe(true);
      expect(service.isEnabled('flag4')).toBe(false);
      
      delete process.env.FEATURE_FLAGS;
    });

    it('should handle empty FEATURE_FLAGS', () => {
      process.env.FEATURE_FLAGS = '';
      const service = new FeatureFlagService();
      
      expect(service.isEnabled('any_flag')).toBe(false);
      expect(service.getEnabledFlags()).toEqual([]);
      
      delete process.env.FEATURE_FLAGS;
    });
  });
});

describe('MockFeatureFlagService', () => {
  it('should work with provided flags', () => {
    const service = new MockFeatureFlagService(['test_flag']);
    expect(service.isEnabled('test_flag')).toBe(true);
    expect(service.isEnabled('other_flag')).toBe(false);
  });

  it('should return empty array when no flags provided', () => {
    const service = new MockFeatureFlagService();
    expect(service.getEnabledFlags()).toEqual([]);
  });
});

describe('mockFeatureFlags default instance', () => {
  it('should have alpha_features enabled by default', () => {
    expect(mockFeatureFlags.isEnabled('alpha_features')).toBe(true);
  });
});