/**
 * Tests for CollaboratorManagement Component
 * FE-TEST-007: Test collaborator management component
 */

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 { CollaboratorManagement } from './CollaboratorManagement';
import { getCollaborators } from '../services/playlistService';

// Mock dependencies
vi.mock('../services/playlistService', () => ({
  getCollaborators: vi.fn(),
}));

vi.mock('./CollaboratorList', () => ({
  CollaboratorList: ({ collaborators, canManage }: any) => (
    <div data-testid="collaborator-list">
      {collaborators.length > 0 ? (
        <ul>
          {collaborators.map((c: any) => (
            <li key={c.id}>{c.user?.username || c.user_id}</li>
          ))}
        </ul>
      ) : (
        <p>Aucun collaborateur</p>
      )}
      {canManage && <button>Manage</button>}
    </div>
  ),
}));

vi.mock('./AddCollaboratorModal', () => ({
  AddCollaboratorModal: ({ open, onClose, onAdded }: any) =>
    open ? (
      <div data-testid="add-collaborator-modal">
        <button onClick={onClose}>Close</button>
        <button onClick={onAdded}>Add</button>
      </div>
    ) : null,
}));

const createTestQueryClient = () =>
  new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

const TestWrapper = ({ children }: { children: React.ReactNode }) => {
  const queryClient = createTestQueryClient();
  return (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  );
};

const mockCollaborators = [
  {
    id: '1',
    playlist_id: '1',
    user_id: '2',
    permission: 'read',
    created_at: new Date().toISOString(),
    user: {
      id: '2',
      username: 'collaborator1',
    },
  },
  {
    id: '2',
    playlist_id: '1',
    user_id: '3',
    permission: 'write',
    created_at: new Date().toISOString(),
    user: {
      id: '3',
      username: 'collaborator2',
    },
  },
];

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

  it('should render collaborator management', () => {
    vi.mocked(getCollaborators).mockResolvedValue(mockCollaborators);

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" />
      </TestWrapper>,
    );

    expect(screen.getByText('Collaborateurs')).toBeInTheDocument();
  });

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

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" />
      </TestWrapper>,
    );

    // Loading spinner should be present
    expect(screen.getByText('Collaborateurs')).toBeInTheDocument();
  });

  it('should display collaborators list', async () => {
    vi.mocked(getCollaborators).mockResolvedValue(mockCollaborators);

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" />
      </TestWrapper>,
    );

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

  it('should show collaborator count', async () => {
    vi.mocked(getCollaborators).mockResolvedValue(mockCollaborators);

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" />
      </TestWrapper>,
    );

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

  it('should show add button when canManage is true', async () => {
    vi.mocked(getCollaborators).mockResolvedValue(mockCollaborators);

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" canManage={true} />
      </TestWrapper>,
    );

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

  it('should not show add button when canManage is false', async () => {
    vi.mocked(getCollaborators).mockResolvedValue(mockCollaborators);

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" canManage={false} />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(screen.queryByText('Ajouter')).not.toBeInTheDocument();
    });
  });

  it('should open add modal when add button is clicked', async () => {
    const user = userEvent.setup();
    vi.mocked(getCollaborators).mockResolvedValue(mockCollaborators);

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" canManage={true} />
      </TestWrapper>,
    );

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

    const addButton = screen.getByText('Ajouter');
    await user.click(addButton);

    expect(screen.getByTestId('add-collaborator-modal')).toBeInTheDocument();
  });

  it('should refetch collaborators after adding', async () => {
    const user = userEvent.setup();
    vi.mocked(getCollaborators).mockResolvedValue(mockCollaborators);

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" canManage={true} />
      </TestWrapper>,
    );

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

    const addButton = screen.getByText('Ajouter');
    await user.click(addButton);

    const addModal = screen.getByTestId('add-collaborator-modal');
    const addButtonInModal = screen.getByText('Add');
    await user.click(addButtonInModal);

    // Should refetch
    await waitFor(() => {
      expect(getCollaborators).toHaveBeenCalledTimes(2);
    });
  });

  it('should show error state', async () => {
    vi.mocked(getCollaborators).mockRejectedValue(new Error('Failed to load'));

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(
        screen.getByText(/erreur lors du chargement des collaborateurs/i),
      ).toBeInTheDocument();
    });
  });

  it('should show retry button on error', async () => {
    const user = userEvent.setup();
    vi.mocked(getCollaborators).mockRejectedValue(new Error('Failed to load'));

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" />
      </TestWrapper>,
    );

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

    const retryButton = screen.getByText(/réessayer/i);
    await user.click(retryButton);

    expect(getCollaborators).toHaveBeenCalled();
  });

  it('should display empty state when no collaborators', async () => {
    vi.mocked(getCollaborators).mockResolvedValue([]);

    render(
      <TestWrapper>
        <CollaboratorManagement playlistId="1" />
      </TestWrapper>,
    );

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