import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { BrowserRouter } from 'react-router-dom';
import { SettingsPage } from './SettingsPage';
import * as settingsService from '../services/settingsService';
import { UserSettings } from '../types/settings';
import { ToastProvider } from '@/components/feedback/ToastProvider';

// Mock ResizeObserver for tests
global.ResizeObserver = vi.fn().mockImplementation(() => ({
  observe: vi.fn(),
  unobserve: vi.fn(),
  disconnect: vi.fn(),
}));

// Mock settingsService
vi.mock('../services/settingsService', () => ({
  getSettings: vi.fn(),
  updateSettings: vi.fn(),
}));

// Mock useAuthStore
vi.mock('@/features/auth/store/authStore', () => ({
  useAuthStore: () => ({
    user: {
      id: 1,
      username: 'testuser',
      email: 'test@example.com',
    },
  }),
}));

// Mock SettingsTabs
vi.mock('../components/SettingsTabs', () => ({
  SettingsTabs: ({
    settings,
    onChange,
  }: {
    settings: UserSettings;
    onChange: (s: UserSettings) => void;
  }) => (
    <div data-testid="settings-tabs">
      <button
        onClick={() =>
          onChange({
            ...settings,
            preferences: { ...settings.preferences, language: 'fr' },
          })
        }
      >
        Change Language
      </button>
    </div>
  ),
}));

const TestWrapper = ({ children }: { children: React.ReactNode }) => (
  <BrowserRouter>
    <ToastProvider>{children}</ToastProvider>
  </BrowserRouter>
);

describe('SettingsPage', () => {
  const mockSettings: UserSettings = {
    notifications: {
      email_notifications: true,
      push_notifications: true,
      browser_notifications: true,
      email_on_follow: true,
      email_on_like: true,
      email_on_comment: true,
      email_on_message: true,
      email_on_mention: true,
      email_marketing: false,
    },
    privacy: {
      allow_search_indexing: true,
      show_activity: true,
    },
    content: {
      explicit_content: false,
      autoplay: true,
    },
    preferences: {
      language: 'en',
      timezone: 'UTC',
      theme: 'auto',
    },
  };

  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should load and display settings', async () => {
    vi.mocked(settingsService.getSettings).mockResolvedValue(mockSettings);

    render(
      <TestWrapper>
        <SettingsPage />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(screen.getByText('Paramètres')).toBeInTheDocument();
    });

    expect(
      screen.getByText('Gérez vos paramètres de compte et préférences'),
    ).toBeInTheDocument();
    expect(screen.getByTestId('settings-tabs')).toBeInTheDocument();
    expect(screen.getByText('Sauvegarder')).toBeInTheDocument();
  });

  it('should display loading state', () => {
    vi.mocked(settingsService.getSettings).mockImplementation(
      () => new Promise(() => {}), // Never resolves
    );

    render(
      <TestWrapper>
        <SettingsPage />
      </TestWrapper>,
    );

    // Should show loading spinner
    expect(screen.queryByText('Paramètres')).not.toBeInTheDocument();
  });

  it('should save settings on button click', async () => {
    vi.mocked(settingsService.getSettings).mockResolvedValue(mockSettings);
    vi.mocked(settingsService.updateSettings).mockResolvedValue();

    render(
      <TestWrapper>
        <SettingsPage />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(screen.getByText('Sauvegarder')).toBeInTheDocument();
    });

    const saveButton = screen.getByText('Sauvegarder');
    fireEvent.click(saveButton);

    await waitFor(() => {
      expect(settingsService.updateSettings).toHaveBeenCalledWith(
        1,
        mockSettings,
      );
    });
  });

  it('should display validation errors', async () => {
    const invalidSettings: UserSettings = {
      ...mockSettings,
      preferences: {
        ...mockSettings.preferences,
        language: 'invalid-lang' as any, // Invalid language
      },
    };

    vi.mocked(settingsService.getSettings).mockResolvedValue(invalidSettings);

    render(
      <TestWrapper>
        <SettingsPage />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(screen.getByText('Sauvegarder')).toBeInTheDocument();
    });

    const saveButton = screen.getByText('Sauvegarder');
    fireEvent.click(saveButton);

    // Validation should prevent save
    await waitFor(() => {
      expect(settingsService.updateSettings).not.toHaveBeenCalled();
    });
  });

  it('should handle load error', async () => {
    vi.mocked(settingsService.getSettings).mockRejectedValue(
      new Error('Failed to load settings'),
    );

    render(
      <TestWrapper>
        <SettingsPage />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(
        screen.getByText('Erreur de chargement des paramètres'),
      ).toBeInTheDocument();
    });
  });

  it('should handle save error', async () => {
    vi.mocked(settingsService.getSettings).mockResolvedValue(mockSettings);
    vi.mocked(settingsService.updateSettings).mockRejectedValue(
      new Error('Failed to save'),
    );

    render(
      <TestWrapper>
        <SettingsPage />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(screen.getByText('Sauvegarder')).toBeInTheDocument();
    });

    const saveButton = screen.getByText('Sauvegarder');
    fireEvent.click(saveButton);

    await waitFor(() => {
      expect(settingsService.updateSettings).toHaveBeenCalled();
    });
  });
});
