import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { AvatarUpload } from './AvatarUpload';
import * as avatarService from '../services/avatarService';

// Mock the avatar service
vi.mock('../services/avatarService');
vi.mock('@/hooks/useToast', () => ({
  useToast: () => ({
    success: vi.fn(),
    error: vi.fn(),
  }),
}));

describe('AvatarUpload', () => {
  const mockUserId = 123;
  const mockAvatarUrl = 'https://example.com/avatar.jpg';
  const mockOnAvatarUpdated = vi.fn();

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

  it('should render with current avatar URL', () => {
    render(
      <AvatarUpload
        userId={mockUserId}
        currentAvatarUrl={mockAvatarUrl}
        onAvatarUpdated={mockOnAvatarUpdated}
      />,
    );

    const img = screen.getByAltText('Avatar');
    expect(img).toHaveAttribute('src', mockAvatarUrl);
  });

  it('should render upload placeholder when no avatar', () => {
    render(<AvatarUpload userId={mockUserId} />);

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

  it('should validate file format', async () => {
    const user = userEvent.setup();
    const { container } = render(<AvatarUpload userId={mockUserId} />);

    const fileInput = container.querySelector(
      'input[type="file"]',
    ) as HTMLInputElement;
    expect(fileInput).toBeInTheDocument();

    const invalidFile = new File(['content'], 'test.txt', {
      type: 'text/plain',
    });

    await user.upload(fileInput, invalidFile);

    // Should show error toast (mocked) and not call uploadAvatar
    await waitFor(() => {
      expect(avatarService.uploadAvatar).not.toHaveBeenCalled();
    });
  });

  it('should validate file size', async () => {
    const user = userEvent.setup();
    const { container } = render(<AvatarUpload userId={mockUserId} />);

    const fileInput = container.querySelector(
      'input[type="file"]',
    ) as HTMLInputElement;
    // Create a file larger than 5MB
    const largeFile = new File(['x'.repeat(6 * 1024 * 1024)], 'large.jpg', {
      type: 'image/jpeg',
    });

    await user.upload(fileInput, largeFile);

    // Should show error toast (mocked) and not call uploadAvatar
    await waitFor(() => {
      expect(avatarService.uploadAvatar).not.toHaveBeenCalled();
    });
  });

  it('should upload valid file', async () => {
    const user = userEvent.setup();
    const mockResponse = { avatar_url: 'https://example.com/new-avatar.jpg' };
    vi.mocked(avatarService.uploadAvatar).mockResolvedValue(mockResponse);

    render(
      <AvatarUpload
        userId={mockUserId}
        onAvatarUpdated={mockOnAvatarUpdated}
      />,
    );

    const fileInput = screen
      .getByRole('button', { name: /changer/i })
      .closest('div')
      ?.querySelector('input[type="file"]') as HTMLInputElement;
    const validFile = new File(['content'], 'test.jpg', { type: 'image/jpeg' });

    // Simulate file selection
    await user.upload(fileInput, validFile);

    await waitFor(() => {
      expect(avatarService.uploadAvatar).toHaveBeenCalledWith(
        mockUserId,
        validFile,
      );
      expect(mockOnAvatarUpdated).toHaveBeenCalledWith(mockResponse.avatar_url);
    });
  });

  it('should delete avatar', async () => {
    const user = userEvent.setup();
    vi.mocked(avatarService.deleteAvatar).mockResolvedValue();

    render(
      <AvatarUpload
        userId={mockUserId}
        currentAvatarUrl={mockAvatarUrl}
        onAvatarUpdated={mockOnAvatarUpdated}
      />,
    );

    const deleteButton = screen.getByText('Supprimer');
    await user.click(deleteButton);

    await waitFor(() => {
      expect(avatarService.deleteAvatar).toHaveBeenCalledWith(mockUserId);
      expect(mockOnAvatarUpdated).toHaveBeenCalledWith('');
    });
  });

  it('should show delete button only when avatar exists', () => {
    render(<AvatarUpload userId={mockUserId} />);

    expect(screen.queryByText('Supprimer')).not.toBeInTheDocument();
  });

  it('should handle drag and drop', async () => {
    const user = userEvent.setup();
    const mockResponse = { avatar_url: 'https://example.com/new-avatar.jpg' };
    vi.mocked(avatarService.uploadAvatar).mockResolvedValue(mockResponse);

    render(
      <AvatarUpload
        userId={mockUserId}
        onAvatarUpdated={mockOnAvatarUpdated}
      />,
    );

    const dropZone = screen.getByText('Cliquez pour uploader').closest('div');
    expect(dropZone).toBeInTheDocument();

    const validFile = new File(['content'], 'test.jpg', { type: 'image/jpeg' });

    // Simulate drag and drop
    await user.upload(dropZone!, validFile);

    await waitFor(() => {
      expect(avatarService.uploadAvatar).toHaveBeenCalledWith(
        mockUserId,
        validFile,
      );
    });
  });
});
