import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { CreatePlaylistDialog } from './CreatePlaylistDialog';
import * as playlistService from '../services/playlistService';
import { vi as viMock } from 'vitest';
import { ToastProvider } from '@/components/feedback/ToastProvider';

vi.mock('../services/playlistService');

const mockToast = {
  toast: vi.fn(),
  success: vi.fn(),
  error: vi.fn(),
  warning: vi.fn(),
  info: vi.fn(),
};

vi.mock('@/hooks/useToast', () => ({
  useToast: () => mockToast,
}));

const renderWithProviders = (ui: React.ReactElement) => {
  return render(<ToastProvider>{ui}</ToastProvider>);
};

describe('CreatePlaylistDialog', () => {
  const mockOnCreated = vi.fn();
  const mockOnOpenChange = vi.fn();

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

  it('should render dialog when open', () => {
    renderWithProviders(
      <CreatePlaylistDialog
        open={true}
        onOpenChange={mockOnOpenChange}
        onCreated={mockOnCreated}
      />,
    );

    expect(screen.getByText('Créer une playlist')).toBeInTheDocument();
  });

  it('should not render when closed', () => {
    render(
      <CreatePlaylistDialog
        open={false}
        onOpenChange={mockOnOpenChange}
        onCreated={mockOnCreated}
      />,
    );

    expect(screen.queryByText('Créer une playlist')).not.toBeInTheDocument();
  });

  it('should create playlist on form submit', async () => {
    const user = userEvent.setup();
    const mockPlaylist = {
      id: 1,
      user_id: 1,
      title: 'New Playlist',
      is_public: true,
      track_count: 0,
      created_at: '2024-01-01T00:00:00Z',
      updated_at: '2024-01-01T00:00:00Z',
    };

    viMock
      .mocked(playlistService.createPlaylist)
      .mockResolvedValue(mockPlaylist);

    renderWithProviders(
      <CreatePlaylistDialog
        open={true}
        onOpenChange={mockOnOpenChange}
        onCreated={mockOnCreated}
      />,
    );

    const titleInput = screen.getByPlaceholderText('Ma nouvelle playlist');
    await user.type(titleInput, 'New Playlist');

    const submitButton = screen.getByRole('button', { name: /créer/i });
    await user.click(submitButton);

    await waitFor(() => {
      expect(playlistService.createPlaylist).toHaveBeenCalledWith(
        'New Playlist',
        undefined,
        true,
      );
    });
  });

  it('should validate required fields', async () => {
    const user = userEvent.setup();

    renderWithProviders(
      <CreatePlaylistDialog
        open={true}
        onOpenChange={mockOnOpenChange}
        onCreated={mockOnCreated}
      />,
    );

    const submitButton = screen.getByRole('button', { name: /créer/i });
    await user.click(submitButton);

    await waitFor(() => {
      expect(screen.getByText(/le titre est requis/i)).toBeInTheDocument();
    });

    expect(playlistService.createPlaylist).not.toHaveBeenCalled();
  });

  it('should handle creation error', async () => {
    const user = userEvent.setup();
    const error = new playlistService.PlaylistError(
      'Creation failed',
      'VALIDATION',
    );

    viMock.mocked(playlistService.createPlaylist).mockRejectedValue(error);

    renderWithProviders(
      <CreatePlaylistDialog
        open={true}
        onOpenChange={mockOnOpenChange}
        onCreated={mockOnCreated}
      />,
    );

    const titleInput = screen.getByPlaceholderText('Ma nouvelle playlist');
    await user.type(titleInput, 'New Playlist');

    const submitButton = screen.getByRole('button', { name: /créer/i });
    await user.click(submitButton);

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

  it('should close dialog on cancel', async () => {
    const user = userEvent.setup();

    renderWithProviders(
      <CreatePlaylistDialog
        open={true}
        onOpenChange={mockOnOpenChange}
        onCreated={mockOnCreated}
      />,
    );

    const cancelButton = screen.getByRole('button', { name: /annuler/i });
    await user.click(cancelButton);

    expect(mockOnOpenChange).toHaveBeenCalledWith(false);
  });
});
