/**
 * Tests pour le hook usePlaylistPermissions
 * T0485: Create Playlist Permission Frontend Checks
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { usePlaylistPermissions } from './usePlaylistPermissions';
import { useCollaborators } from './usePlaylist';
import { useAuthStore } from '@/features/auth/store/authStore';
import type { Playlist } from '../types';

// Mock des hooks
vi.mock('./usePlaylist', () => ({
  useCollaborators: vi.fn(),
  usePlaylist: vi.fn(),
  useCreatePlaylist: vi.fn(),
  useUpdatePlaylist: vi.fn(),
  useDeletePlaylist: vi.fn(),
  usePlaylists: vi.fn(),
  useAddCollaborator: vi.fn(),
  useRemoveCollaborator: vi.fn(),
  useUpdateCollaboratorPermission: vi.fn(),
}));

vi.mock('@/features/auth/store/authStore', () => ({
  useAuthStore: vi.fn((selector) => {
    const state = { user: { id: 1 } };
    return selector(state);
  }),
}));

function createWrapper() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

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

const mockPlaylist: Playlist = {
  id: 1,
  user_id: 1,
  title: 'Test Playlist',
  description: 'Test Description',
  is_public: false,
  cover_url: null,
  track_count: 0,
  created_at: '2024-01-01T00:00:00Z',
  updated_at: '2024-01-01T00:00:00Z',
  tracks: [],
};

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

  it('should return all false permissions when playlist is null', () => {
    vi.mocked(useAuthStore).mockImplementation((selector: any) => {
      const state = { user: { id: 1 } };
      return selector(state);
    });
    vi.mocked(useCollaborators).mockReturnValue({
      data: [],
      isLoading: false,
      isError: false,
      error: null,
      refetch: vi.fn(),
    } as any);

    const { result } = renderHook(() => usePlaylistPermissions(null), {
      wrapper: createWrapper(),
    });

    expect(result.current.canEdit).toBe(false);
    expect(result.current.canDelete).toBe(false);
    expect(result.current.canAddTracks).toBe(false);
    expect(result.current.canRemoveTracks).toBe(false);
    expect(result.current.canManageCollaborators).toBe(false);
    expect(result.current.canRead).toBe(false);
    expect(result.current.isOwner).toBe(false);
  });

  it('should return all false permissions when playlist is undefined', () => {
    vi.mocked(useAuthStore).mockImplementation((selector: any) => {
      const state = { user: { id: 1 } };
      return selector(state);
    });
    vi.mocked(useCollaborators).mockReturnValue({
      data: [],
      isLoading: false,
      isError: false,
      error: null,
      refetch: vi.fn(),
    } as any);

    const { result } = renderHook(() => usePlaylistPermissions(undefined), {
      wrapper: createWrapper(),
    });

    expect(result.current.canEdit).toBe(false);
    expect(result.current.canDelete).toBe(false);
    expect(result.current.canAddTracks).toBe(false);
    expect(result.current.canRemoveTracks).toBe(false);
    expect(result.current.canManageCollaborators).toBe(false);
    expect(result.current.canRead).toBe(false);
    expect(result.current.isOwner).toBe(false);
  });

  it('should return true for all permissions when user is owner', () => {
    vi.mocked(useAuthStore).mockImplementation((selector: any) => {
      const state = { user: { id: 1 } };
      return selector(state);
    });
    vi.mocked(useCollaborators).mockReturnValue({
      data: [],
      isLoading: false,
      isError: false,
      error: null,
      refetch: vi.fn(),
    } as any);

    const { result } = renderHook(() => usePlaylistPermissions(mockPlaylist), {
      wrapper: createWrapper(),
    });

    expect(result.current.canEdit).toBe(true);
    expect(result.current.canDelete).toBe(true);
    expect(result.current.canAddTracks).toBe(true);
    expect(result.current.canRemoveTracks).toBe(true);
    expect(result.current.canManageCollaborators).toBe(true);
    expect(result.current.canRead).toBe(true);
    expect(result.current.isOwner).toBe(true);
  });

  it('should return correct permissions for collaborator with admin permission', () => {
    vi.mocked(useAuthStore).mockImplementation((selector: any) => {
      const state = { user: { id: 4 } };
      return selector(state);
    });
    vi.mocked(useCollaborators).mockReturnValue({
      data: [
        {
          id: 1,
          playlist_id: 1,
          user_id: 4,
          permission: 'admin',
          created_at: '2024-01-01T00:00:00Z',
          updated_at: '2024-01-01T00:00:00Z',
        },
      ],
      isLoading: false,
      isError: false,
      error: null,
      refetch: vi.fn(),
    } as any);

    const { result } = renderHook(() => usePlaylistPermissions(mockPlaylist), {
      wrapper: createWrapper(),
    });

    expect(result.current.canEdit).toBe(true);
    expect(result.current.canDelete).toBe(false);
    expect(result.current.canAddTracks).toBe(true);
    expect(result.current.canRemoveTracks).toBe(true);
    expect(result.current.canManageCollaborators).toBe(false);
    expect(result.current.canRead).toBe(true);
    expect(result.current.isOwner).toBe(false);
  });

  it('should return correct permissions for collaborator with write permission', () => {
    vi.mocked(useAuthStore).mockImplementation((selector: any) => {
      const state = { user: { id: 3 } };
      return selector(state);
    });
    vi.mocked(useCollaborators).mockReturnValue({
      data: [
        {
          id: 1,
          playlist_id: 1,
          user_id: 3,
          permission: 'write',
          created_at: '2024-01-01T00:00:00Z',
          updated_at: '2024-01-01T00:00:00Z',
        },
      ],
      isLoading: false,
      isError: false,
      error: null,
      refetch: vi.fn(),
    } as any);

    const { result } = renderHook(() => usePlaylistPermissions(mockPlaylist), {
      wrapper: createWrapper(),
    });

    expect(result.current.canEdit).toBe(true);
    expect(result.current.canDelete).toBe(false);
    expect(result.current.canAddTracks).toBe(true);
    expect(result.current.canRemoveTracks).toBe(true);
    expect(result.current.canManageCollaborators).toBe(false);
    expect(result.current.canRead).toBe(true);
    expect(result.current.isOwner).toBe(false);
  });

  it('should return correct permissions for collaborator with read permission', () => {
    vi.mocked(useAuthStore).mockImplementation((selector: any) => {
      const state = { user: { id: 2 } };
      return selector(state);
    });
    vi.mocked(useCollaborators).mockReturnValue({
      data: [
        {
          id: 1,
          playlist_id: 1,
          user_id: 2,
          permission: 'read',
          created_at: '2024-01-01T00:00:00Z',
          updated_at: '2024-01-01T00:00:00Z',
        },
      ],
      isLoading: false,
      isError: false,
      error: null,
      refetch: vi.fn(),
    } as any);

    const { result } = renderHook(() => usePlaylistPermissions(mockPlaylist), {
      wrapper: createWrapper(),
    });

    expect(result.current.canEdit).toBe(false);
    expect(result.current.canDelete).toBe(false);
    expect(result.current.canAddTracks).toBe(false);
    expect(result.current.canRemoveTracks).toBe(false);
    expect(result.current.canManageCollaborators).toBe(false);
    expect(result.current.canRead).toBe(true);
    expect(result.current.isOwner).toBe(false);
  });

  it('should return false permissions for non-collaborator on private playlist', () => {
    vi.mocked(useAuthStore).mockImplementation((selector: any) => {
      const state = { user: { id: 5 } };
      return selector(state);
    });
    vi.mocked(useCollaborators).mockReturnValue({
      data: [],
      isLoading: false,
      isError: false,
      error: null,
      refetch: vi.fn(),
    } as any);

    const { result } = renderHook(() => usePlaylistPermissions(mockPlaylist), {
      wrapper: createWrapper(),
    });

    expect(result.current.canEdit).toBe(false);
    expect(result.current.canDelete).toBe(false);
    expect(result.current.canAddTracks).toBe(false);
    expect(result.current.canRemoveTracks).toBe(false);
    expect(result.current.canManageCollaborators).toBe(false);
    expect(result.current.canRead).toBe(false);
    expect(result.current.isOwner).toBe(false);
  });

  it('should return canRead true for public playlist even for non-collaborator', () => {
    const publicPlaylist: Playlist = {
      ...mockPlaylist,
      is_public: true,
    };

    vi.mocked(useAuthStore).mockImplementation((selector: any) => {
      const state = { user: { id: 5 } };
      return selector(state);
    });
    vi.mocked(useCollaborators).mockReturnValue({
      data: [],
      isLoading: false,
      isError: false,
      error: null,
      refetch: vi.fn(),
    } as any);

    const { result } = renderHook(
      () => usePlaylistPermissions(publicPlaylist),
      {
        wrapper: createWrapper(),
      },
    );

    expect(result.current.canRead).toBe(true);
    expect(result.current.canEdit).toBe(false);
    expect(result.current.canDelete).toBe(false);
  });

  it('should return false permissions when user is null', () => {
    vi.mocked(useAuthStore).mockImplementation((selector: any) => {
      const state = { user: null };
      return selector(state);
    });
    vi.mocked(useCollaborators).mockReturnValue({
      data: [],
      isLoading: false,
      isError: false,
      error: null,
      refetch: vi.fn(),
    } as any);

    const { result } = renderHook(() => usePlaylistPermissions(mockPlaylist), {
      wrapper: createWrapper(),
    });

    expect(result.current.canEdit).toBe(false);
    expect(result.current.canDelete).toBe(false);
    expect(result.current.canAddTracks).toBe(false);
    expect(result.current.canRemoveTracks).toBe(false);
    expect(result.current.canManageCollaborators).toBe(false);
    expect(result.current.canRead).toBe(false);
    expect(result.current.isOwner).toBe(false);
  });
});
