import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AvatarUpload } from './avatar-upload';

// Mock useToast
const mockShowSuccess = vi.fn();
const mockShowError = vi.fn();

vi.mock('@/hooks/useToast', () => ({
  useToast: () => ({
    success: mockShowSuccess,
    error: mockShowError,
  }),
}));

// Mock avatarService
vi.mock('@/features/profile/services/avatarService', () => ({
  uploadAvatar: vi.fn().mockResolvedValue({ avatar_url: 'new-avatar.jpg' }),
  deleteAvatar: vi.fn().mockResolvedValue({}),
}));

describe('AvatarUpload Component', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renders avatar upload component', () => {
    render(<AvatarUpload userId="123" />);

    expect(screen.getByRole('button', { name: /Cliquez pour uploader/i })).toBeInTheDocument();
  });

  it('renders current avatar when provided', () => {
    render(<AvatarUpload userId="123" currentAvatarUrl="avatar.jpg" />);

    const image = screen.getByAltText('Avatar preview');
    expect(image).toBeInTheDocument();
    expect(image).toHaveAttribute('src', 'avatar.jpg');
  });

  it('shows upload button when no avatar', () => {
    render(<AvatarUpload userId="123" />);

    expect(screen.getByText(/Cliquez pour uploader/i)).toBeInTheDocument();
  });

  it('shows change button when avatar exists', () => {
    render(<AvatarUpload userId="123" currentAvatarUrl="avatar.jpg" />);

    expect(screen.getByText(/Changer/i)).toBeInTheDocument();
  });

  it('handles file selection', async () => {
    const mockOnAvatarUpdated = vi.fn();
    const file = new File(['test'], 'test.jpg', { type: 'image/jpeg' });

    render(<AvatarUpload userId="123" onAvatarUpdated={mockOnAvatarUpdated} />);

    const input = document.querySelector('input[type="file"]');
    expect(input).toBeInTheDocument();
    if (input) {
      Object.defineProperty(input, 'files', {
        value: [file],
        writable: false,
      });

      fireEvent.change(input);

      await waitFor(
        () => {
          expect(mockOnAvatarUpdated).toHaveBeenCalled();
        },
        { timeout: 2000 },
      );
    }
  });

  it('validates file type', async () => {
    const file = new File(['test'], 'test.txt', { type: 'text/plain' });

    render(<AvatarUpload userId="123" />);

    const input = document.querySelector('input[type="file"]');

    if (input) {
      Object.defineProperty(input, 'files', {
        value: [file],
        writable: false,
      });

      fireEvent.change(input);

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

  it('validates file size', async () => {
    const largeFile = new File(['x'.repeat(10 * 1024 * 1024)], 'large.jpg', {
      type: 'image/jpeg',
    });

    render(<AvatarUpload userId="123" maxSize={5 * 1024 * 1024} />);

    const input = document.querySelector('input[type="file"]');

    if (input) {
      Object.defineProperty(input, 'files', {
        value: [largeFile],
        writable: false,
      });

      fireEvent.change(input);

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

  it('handles delete action', async () => {
    const mockOnAvatarDeleted = vi.fn();

    render(
      <AvatarUpload
        userId="123"
        currentAvatarUrl="avatar.jpg"
        onAvatarDeleted={mockOnAvatarDeleted}
      />,
    );

    const deleteButton = screen.getByText(/Supprimer/i);
    fireEvent.click(deleteButton);

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

  it('disables when disabled prop is true', () => {
    render(<AvatarUpload userId="123" disabled={true} />);

    const button = screen.getByText(/Cliquez pour uploader/i);
    expect(button).toBeDisabled();
  });
});
