import { describe, it, expect, beforeEach, vi } from 'vitest';
import { SettingsService } from './settings-service';
import { useSettingsStore } from '@/store/use-settings';
import { LLMService } from './llm-service';

// Mock settings store
vi.mock('@/store/use-settings', () => ({
  useSettingsStore: {
    getState: vi.fn(),
  },
}));

// Mock LLM service
vi.mock('./llm-service', () => ({
  LLMService: {
    validateConnection: vi.fn(),
  },
}));

describe('SettingsService', () => {
  const mockGetState = useSettingsStore.getState as any;
  const mockActions = {
    setApiKey: vi.fn(),
    setBaseUrl: vi.fn(),
    setModelName: vi.fn(),
    clearSettings: vi.fn(),
  };

  beforeEach(() => {
    vi.clearAllMocks();
    mockGetState.mockReturnValue({
      apiKey: '',
      baseUrl: 'https://api.openai.com/v1',
      modelName: 'gpt-4-turbo-preview',
      isConfigured: false,
      actions: mockActions,
    });
  });

  describe('saveProviderSettings', () => {
    it('saves settings to store by calling actions', () => {
      const settings = {
        apiKey: 'sk-test-key',
        baseUrl: 'https://api.openai.com/v1',
        modelName: 'gpt-4o',
      };

      SettingsService.saveProviderSettings(settings);

      expect(mockActions.setApiKey).toHaveBeenCalledWith('sk-test-key');
      expect(mockActions.setBaseUrl).toHaveBeenCalledWith('https://api.openai.com/v1');
      expect(mockActions.setModelName).toHaveBeenCalledWith('gpt-4o');
    });
  });

  describe('getProviderSettings', () => {
    it('returns current settings from store', () => {
      mockGetState.mockReturnValue({
        apiKey: 'sk-current-key',
        baseUrl: 'https://api.deepseek.com/v1',
        modelName: 'deepseek-chat',
        isConfigured: true,
        actions: mockActions,
      });

      const settings = SettingsService.getProviderSettings();

      expect(settings).toEqual({
        apiKey: 'sk-current-key',
        baseUrl: 'https://api.deepseek.com/v1',
        modelName: 'deepseek-chat',
      });
    });
  });

  describe('validateProviderSettings', () => {
    it('returns valid when all fields are present', () => {
      const settings = {
        apiKey: 'sk-test-key',
        baseUrl: 'https://api.openai.com/v1',
        modelName: 'gpt-4o',
      };

      const result = SettingsService.validateProviderSettings(settings);

      expect(result).toEqual({ isValid: true });
    });

    it('returns invalid when API key is empty', () => {
      const settings = {
        apiKey: '',
        baseUrl: 'https://api.openai.com/v1',
        modelName: 'gpt-4o',
      };

      const result = SettingsService.validateProviderSettings(settings);

      expect(result).toEqual({
        isValid: false,
        error: 'API Key is required',
      });
    });

    it('returns invalid when API key is whitespace only', () => {
      const settings = {
        apiKey: '   ',
        baseUrl: 'https://api.openai.com/v1',
        modelName: 'gpt-4o',
      };

      const result = SettingsService.validateProviderSettings(settings);

      expect(result).toEqual({
        isValid: false,
        error: 'API Key is required',
      });
    });

    it('returns invalid when base URL is invalid', () => {
      const settings = {
        apiKey: 'sk-test-key',
        baseUrl: 'not-a-valid-url',
        modelName: 'gpt-4o',
      };

      const result = SettingsService.validateProviderSettings(settings);

      expect(result).toEqual({
        isValid: false,
        error: 'Base URL must be a valid URL',
      });
    });

    it('returns invalid when model name is empty', () => {
      const settings = {
        apiKey: 'sk-test-key',
        baseUrl: 'https://api.openai.com/v1',
        modelName: '',
      };

      const result = SettingsService.validateProviderSettings(settings);

      expect(result).toEqual({
        isValid: false,
        error: 'Model Name is required',
      });
    });
  });

  describe('validateProviderConnection', () => {
    it('returns invalid when settings structure is invalid', async () => {
      const settings = {
        apiKey: '',
        baseUrl: 'https://api.openai.com/v1',
        modelName: 'gpt-4o',
      };

      // First save the invalid settings
      mockGetState.mockReturnValue({
        ...settings,
        isConfigured: false,
        actions: mockActions,
      });

      const result = await SettingsService.validateProviderConnection();

      expect(result).toEqual({
        isValid: false,
        error: 'API Key is required',
      });
    });

    it('calls LLMService.validateConnection when structure is valid', async () => {
      const settings = {
        apiKey: 'sk-test-key',
        baseUrl: 'https://api.openai.com/v1',
        modelName: 'gpt-4o',
      };

      mockGetState.mockReturnValue({
        ...settings,
        isConfigured: true,
        actions: mockActions,
      });

      vi.mocked(LLMService.validateConnection).mockResolvedValue({ isValid: true });

      const result = await SettingsService.validateProviderConnection();

      expect(LLMService.validateConnection).toHaveBeenCalledWith(
        'https://api.openai.com/v1',
        'sk-test-key',
        'gpt-4o'
      );
      // Service maps detailed result to legacy format
      expect(result).toEqual({ isValid: true });
    });

    it('returns error when connection fails', async () => {
      const settings = {
        apiKey: 'sk-invalid-key',
        baseUrl: 'https://api.openai.com/v1',
        modelName: 'gpt-4o',
      };

      mockGetState.mockReturnValue({
        ...settings,
        isConfigured: true,
        actions: mockActions,
      });

      vi.mocked(LLMService.validateConnection).mockResolvedValue({
        isValid: false,
        errorMessage: 'Your API key appears to be invalid or expired.',
      });

      const result = await SettingsService.validateProviderConnection();

      expect(result).toEqual({
        isValid: false,
        error: 'Your API key appears to be invalid or expired.',
      });
    });

    it('returns error with message when connection throws', async () => {
      const settings = {
        apiKey: 'sk-test-key',
        baseUrl: 'https://api.openai.com/v1',
        modelName: 'gpt-4o',
      };

      mockGetState.mockReturnValue({
        ...settings,
        isConfigured: true,
        actions: mockActions,
      });

      const networkError = new Error('Network error');
      vi.mocked(LLMService.validateConnection).mockRejectedValue(networkError);

      const result = await SettingsService.validateProviderConnection();

      expect(result).toEqual({
        isValid: false,
        error: 'Network error',
      });
    });
  });

  describe('isProviderConfigured', () => {
    it('returns true when provider is configured', () => {
      mockGetState.mockReturnValue({
        apiKey: 'sk-test-key',
        baseUrl: 'https://api.openai.com/v1',
        modelName: 'gpt-4o',
        isConfigured: true,
        actions: mockActions,
      });

      expect(SettingsService.isProviderConfigured()).toBe(true);
    });

    it('returns false when provider is not configured', () => {
      mockGetState.mockReturnValue({
        apiKey: '',
        baseUrl: 'https://api.openai.com/v1',
        modelName: 'gpt-4o',
        isConfigured: false,
        actions: mockActions,
      });

      expect(SettingsService.isProviderConfigured()).toBe(false);
    });
  });

  describe('clearProviderSettings', () => {
    it('calls clearSettings action', () => {
      SettingsService.clearProviderSettings();

      expect(mockActions.clearSettings).toHaveBeenCalled();
    });
  });
});
