/**
 * Tests for ProviderForm Provider Management Features
 * Story 4.4: Provider Switching
 */

import { describe, it, expect, beforeEach, vi } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { ProviderForm } from './provider-form';
import { ProviderManagementService } from '@/services/provider-management-service';
import { useSettingsStore } from '@/store/use-settings';

// Mock services
vi.mock('@/services/settings-service', () => ({
  SettingsService: {
    saveProviderSettingsWithValidation: vi.fn(),
  },
}));

vi.mock('@/services/provider-management-service', () => ({
  ProviderManagementService: {
    addProviderProfile: vi.fn(),
    updateProviderProfile: vi.fn(),
    setActiveProvider: vi.fn(),
    getActiveProvider: vi.fn(),
  },
}));

vi.mock('@/hooks/use-toast', () => ({
  toast: vi.fn(),
}));

import { SettingsService } from '@/services/settings-service';
import { toast } from '@/hooks/use-toast';

describe('ProviderForm Provider Management', () => {
  beforeEach(() => {
    vi.clearAllMocks();

    // Reset store state before each test
    useSettingsStore.setState({
      savedProviders: [],
      activeProviderId: null,
      providerMigrationState: {
        hasMigrated: false,
      },
    });
  });

  describe('Add New Provider mode', () => {
    it('renders provider name input field', () => {
      render(<ProviderForm mode="add" />);

      expect(screen.getByLabelText(/provider name/i)).toBeTruthy();
    });

    it('shows "Save as New Provider" button in add mode', () => {
      render(<ProviderForm mode="add" />);

      expect(screen.getByRole('button', { name: /save as new provider/i })).toBeTruthy();
    });

    it('calls addProviderProfile when saving new provider', async () => {
      const mockProviderId = 'new-provider-id';
      vi.mocked(ProviderManagementService.addProviderProfile).mockReturnValue(mockProviderId);
      // Mock validation to succeed
      vi.mocked(SettingsService.saveProviderSettingsWithValidation).mockResolvedValue({
        isValid: true,
        errorMessage: null,
      });

      render(<ProviderForm mode="add" />);

      fireEvent.change(screen.getByLabelText(/provider name/i), {
        target: { value: 'My New Provider' },
      });
      fireEvent.change(screen.getByLabelText(/base url/i), {
        target: { value: 'https://api.new.com/v1' },
      });
      fireEvent.change(screen.getByLabelText(/model name/i), {
        target: { value: 'new-model' },
      });
      // Use id to be more specific for API key input
      fireEvent.change(screen.getByDisplayValue('') || screen.getByPlaceholderText('sk-...'), {
        target: { value: 'sk-new-key' },
      });

      fireEvent.click(screen.getByRole('button', { name: /save as new provider/i }));

      await waitFor(() => {
        expect(ProviderManagementService.addProviderProfile).toHaveBeenCalledWith({
          name: 'My New Provider',
          baseUrl: 'https://api.new.com/v1',
          apiKey: 'sk-new-key',
          modelName: 'new-model',
        });
      });
    });

    it('auto-selects newly created provider after save', async () => {
      const mockProviderId = 'new-provider-id';
      vi.mocked(ProviderManagementService.addProviderProfile).mockReturnValue(mockProviderId);
      // Mock setActiveProvider to update the store
      vi.mocked(ProviderManagementService.setActiveProvider).mockImplementation((id) => {
        useSettingsStore.setState({ activeProviderId: id });
      });
      vi.mocked(SettingsService.saveProviderSettingsWithValidation).mockResolvedValue({
        isValid: true,
        errorMessage: null,
      });

      render(<ProviderForm mode="add" />);

      fireEvent.change(screen.getByLabelText(/provider name/i), {
        target: { value: 'Test Provider' },
      });
      fireEvent.change(screen.getByLabelText(/base url/i), {
        target: { value: 'https://api.test.com/v1' },
      });
      fireEvent.change(screen.getByLabelText(/model name/i), {
        target: { value: 'test-model' },
      });
      // Use placeholder to find the input
      const apiKeyInput = screen.getByPlaceholderText('sk-...');
      fireEvent.change(apiKeyInput, {
        target: { value: 'sk-test-key' },
      });

      fireEvent.click(screen.getByRole('button', { name: /save as new provider/i }));

      await waitFor(() => {
        expect(useSettingsStore.getState().activeProviderId).toBe(mockProviderId);
      });
    });

    it('shows validation error when provider name is empty', async () => {
      render(<ProviderForm mode="add" />);

      fireEvent.click(screen.getByRole('button', { name: /save as new provider/i }));

      await waitFor(() => {
        expect(toast).toHaveBeenCalledWith(
          expect.objectContaining({
            title: 'Validation Error',
          })
        );
      });
    });
  });

  describe('Edit Provider mode', () => {
    const mockProvider = {
      id: 'edit-provider-id',
      name: 'Provider to Edit',
      baseUrl: 'https://api.edit.com/v1',
      apiKey: 'sk-edit-key',
      modelName: 'edit-model',
      createdAt: '2024-01-24T00:00:00.000Z',
      updatedAt: '2024-01-24T00:00:00.000Z',
    };

    it('pre-fills form with existing provider data', () => {
      render(<ProviderForm mode="edit" provider={mockProvider} />);

      expect(screen.getByLabelText(/provider name/i)).toHaveValue('Provider to Edit');
      expect(screen.getByLabelText(/base url/i)).toHaveValue('https://api.edit.com/v1');
      expect(screen.getByLabelText(/model name/i)).toHaveValue('edit-model');
    });

    it('shows "Update Provider" button in edit mode', () => {
      render(<ProviderForm mode="edit" provider={mockProvider} />);

      expect(screen.getByRole('button', { name: /update provider/i })).toBeTruthy();
    });

    it('calls updateProviderProfile when saving edits', async () => {
      vi.mocked(SettingsService.saveProviderSettingsWithValidation).mockResolvedValue({
        isValid: true,
        errorMessage: null,
      });

      render(<ProviderForm mode="edit" provider={mockProvider} />);

      fireEvent.change(screen.getByLabelText(/provider name/i), {
        target: { value: 'Updated Provider Name' },
      });
      fireEvent.change(screen.getByLabelText(/base url/i), {
        target: { value: 'https://api.updated.com/v1' },
      });

      fireEvent.click(screen.getByRole('button', { name: /update provider/i }));

      await waitFor(() => {
        expect(ProviderManagementService.updateProviderProfile).toHaveBeenCalledWith(
          'edit-provider-id',
          {
            name: 'Updated Provider Name',
            baseUrl: 'https://api.updated.com/v1',
            apiKey: 'sk-edit-key',
            modelName: 'edit-model',
          }
        );
      });
    });

    it('does not change active provider when editing', async () => {
      vi.mocked(SettingsService.saveProviderSettingsWithValidation).mockResolvedValue({
        isValid: true,
        errorMessage: null,
      });
      useSettingsStore.setState({
        activeProviderId: 'other-provider-id',
      });

      render(<ProviderForm mode="edit" provider={mockProvider} />);

      fireEvent.change(screen.getByLabelText(/provider name/i), {
        target: { value: 'Updated Provider' },
      });

      fireEvent.click(screen.getByRole('button', { name: /update provider/i }));

      await waitFor(() => {
        expect(useSettingsStore.getState().activeProviderId).toBe('other-provider-id');
      });
    });
  });

  describe('Connection validation', () => {
    it('validates connection before saving new provider', async () => {
      vi.mocked(SettingsService.saveProviderSettingsWithValidation).mockResolvedValue({
        isValid: true,
        errorMessage: null,
      });

      render(<ProviderForm mode="add" />);

      fireEvent.change(screen.getByLabelText(/provider name/i), {
        target: { value: 'Validated Provider' },
      });
      fireEvent.change(screen.getByLabelText(/base url/i), {
        target: { value: 'https://api.valid.com/v1' },
      });
      fireEvent.change(screen.getByLabelText(/model name/i), {
        target: { value: 'valid-model' },
      });
      const apiKeyInput = screen.getByPlaceholderText('sk-...');
      fireEvent.change(apiKeyInput, {
        target: { value: 'sk-valid-key' },
      });

      fireEvent.click(screen.getByRole('button', { name: /save as new provider/i }));

      await waitFor(() => {
        expect(SettingsService.saveProviderSettingsWithValidation).toHaveBeenCalled();
      });
    });

    it('does not save provider if validation fails', async () => {
      vi.mocked(SettingsService.saveProviderSettingsWithValidation).mockResolvedValue({
        isValid: false,
        errorMessage: 'Invalid API key',
      });

      render(<ProviderForm mode="add" />);

      fireEvent.change(screen.getByLabelText(/provider name/i), {
        target: { value: 'Invalid Provider' },
      });
      fireEvent.change(screen.getByLabelText(/base url/i), {
        target: { value: 'https://api.invalid.com/v1' },
      });
      fireEvent.change(screen.getByLabelText(/model name/i), {
        target: { value: 'invalid-model' },
      });
      const apiKeyInput = screen.getByPlaceholderText('sk-...');
      fireEvent.change(apiKeyInput, {
        target: { value: 'sk-invalid-key' },
      });

      fireEvent.click(screen.getByRole('button', { name: /save as new provider/i }));

      await waitFor(() => {
        expect(ProviderManagementService.addProviderProfile).not.toHaveBeenCalled();
        expect(toast).toHaveBeenCalledWith(
          expect.objectContaining({
            title: 'Connection Failed',
          })
        );
      });
    });
  });
});
