/**
 * Tests unitaires pour ShareLinkButton
 * T0488: Create Playlist Public Share Link
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ShareLinkButton } from './ShareLinkButton';
import { useCreateShareLink } from '../hooks/usePlaylist';
import { useToast } from '@/hooks/useToast';

// Mock hooks
vi.mock('../hooks/usePlaylist', () => ({
  useCreateShareLink: vi.fn(),
}));

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

// Mock navigator.clipboard
Object.assign(navigator, {
  clipboard: {
    writeText: vi.fn().mockResolvedValue(undefined),
  },
});

function createWrapper() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });
  return ({ children }: { children: React.ReactNode }) => (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  );
}

describe('ShareLinkButton', () => {
  const mockMutateAsync = vi.fn();
  const mockToast = vi.fn();

  beforeEach(() => {
    vi.clearAllMocks();
    vi.mocked(useCreateShareLink).mockReturnValue({
      mutateAsync: mockMutateAsync,
      isPending: false,
    } as any);
    vi.mocked(useToast).mockReturnValue({ toast: mockToast });
  });

  it('should render button with generate link text', () => {
    render(<ShareLinkButton playlistId={1} />, { wrapper: createWrapper() });
    expect(screen.getByText(/Générer un lien de partage/i)).toBeInTheDocument();
  });

  it('should generate and copy link when clicked', async () => {
    const user = userEvent.setup();
    const mockShareLink = {
      id: 1,
      playlist_id: 1,
      user_id: 1,
      share_token: 'test-token-123',
      access_count: 0,
      created_at: '2024-01-01T00:00:00Z',
      updated_at: '2024-01-01T00:00:00Z',
    };

    mockMutateAsync.mockResolvedValue(mockShareLink);

    render(<ShareLinkButton playlistId={1} />, { wrapper: createWrapper() });

    const button = screen.getByText(/Générer un lien de partage/i);
    await user.click(button);

    await waitFor(() => {
      expect(mockMutateAsync).toHaveBeenCalledWith(1);
      expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
        expect.stringContaining('playlists/shared/test-token-123'),
      );
      expect(mockToast).toHaveBeenCalledWith(
        expect.objectContaining({ title: 'Lien copié' }),
      );
    });
  });

  it('should show loading state when generating link', () => {
    vi.mocked(useCreateShareLink).mockReturnValue({
      mutateAsync: mockMutateAsync,
      isPending: true,
    } as any);

    render(<ShareLinkButton playlistId={1} />, { wrapper: createWrapper() });
    expect(screen.getByText(/Génération.../i)).toBeInTheDocument();
  });

  it('should show copied state after copying', async () => {
    const user = userEvent.setup();
    const mockShareLink = {
      id: 1,
      playlist_id: 1,
      user_id: 1,
      share_token: 'test-token-123',
      access_count: 0,
      created_at: '2024-01-01T00:00:00Z',
      updated_at: '2024-01-01T00:00:00Z',
    };

    mockMutateAsync.mockResolvedValue(mockShareLink);

    render(<ShareLinkButton playlistId={1} />, { wrapper: createWrapper() });

    const button = screen.getByText(/Générer un lien de partage/i);
    await user.click(button);

    await waitFor(() => {
      expect(screen.getByText(/Copié/i)).toBeInTheDocument();
    });
  });

  it('should handle copy error gracefully', async () => {
    const user = userEvent.setup();
    const mockError = new Error('Failed to copy');
    Object.assign(navigator, {
      clipboard: {
        writeText: vi.fn().mockRejectedValue(mockError),
      },
    });

    const mockShareLink = {
      id: 1,
      playlist_id: 1,
      user_id: 1,
      share_token: 'test-token-123',
      access_count: 0,
      created_at: '2024-01-01T00:00:00Z',
      updated_at: '2024-01-01T00:00:00Z',
    };

    mockMutateAsync.mockResolvedValue(mockShareLink);

    render(<ShareLinkButton playlistId={1} />, { wrapper: createWrapper() });

    const button = screen.getByText(/Générer un lien de partage/i);
    await user.click(button);

    await waitFor(() => {
      expect(mockToast).toHaveBeenCalledWith(
        expect.objectContaining({ variant: 'destructive', title: 'Erreur' }),
      );
    });
  });

  it('should handle generation error gracefully', async () => {
    const user = userEvent.setup();
    const mockError = new Error('Failed to generate link');
    mockMutateAsync.mockRejectedValue(mockError);

    render(<ShareLinkButton playlistId={1} />, { wrapper: createWrapper() });

    const button = screen.getByText(/Générer un lien de partage/i);
    await user.click(button);

    await waitFor(() => {
      expect(mockToast).toHaveBeenCalledWith(
        expect.objectContaining({ variant: 'destructive', title: 'Erreur' }),
      );
    });
  });

  it('should copy existing link when clicked again', async () => {
    const user = userEvent.setup();
    const mockShareLink = {
      id: 1,
      playlist_id: 1,
      user_id: 1,
      share_token: 'test-token-123',
      access_count: 0,
      created_at: '2024-01-01T00:00:00Z',
      updated_at: '2024-01-01T00:00:00Z',
    };

    mockMutateAsync.mockResolvedValue(mockShareLink);

    render(<ShareLinkButton playlistId={1} />, { wrapper: createWrapper() });

    // Première fois: générer et copier
    const button = screen.getByText(/Générer un lien de partage/i);
    await user.click(button);

    await waitFor(() => {
      expect(screen.getByText(/Copier le lien/i)).toBeInTheDocument();
    });

    // Deuxième fois: juste copier
    const copyButton = screen.getByText(/Copier le lien/i);
    await user.click(copyButton);

    await waitFor(() => {
      expect(navigator.clipboard.writeText).toHaveBeenCalledTimes(2);
    });
  });
});
