import React from 'react';
import {render} from '@testing-library/react-native';
import type {Conversation} from '@modules/chats/interfaces';
import {useConversations} from '@modules/chats/store';

import {useSearchConversations} from '../useSearchConversations';

const mockUseConversations = useConversations as jest.Mock;

jest.mock('@modules/chats/store', () => ({
  useConversations: jest.fn(),
}));

const renderHook = (props: Parameters<typeof useSearchConversations>[0]) => {
  let result: ReturnType<typeof useSearchConversations> | undefined;

  const HookWrapper = (
    hookProps: Parameters<typeof useSearchConversations>[0],
  ) => {
    result = useSearchConversations(hookProps);
    return null;
  };

  const rendered = render(React.createElement(HookWrapper, props));

  return {
    getResult: () => result!,
    rerender: (nextProps: Parameters<typeof useSearchConversations>[0]) =>
      rendered.rerender(React.createElement(HookWrapper, nextProps)),
  };
};

const createConversation = (
  overrides: Partial<Conversation> = {},
): Conversation =>
  ({
    id: 'conv-1',
    name: 'General',
    is_channel: true,
    ...overrides,
  } as Conversation);

describe('useSearchConversations', () => {
  beforeEach(() => {
    mockUseConversations.mockReset();
  });

  it('returns all conversations when search text is empty', () => {
    const conversations = [
      createConversation({id: 'c1', name: 'General'}),
      createConversation({
        id: 'c2',
        name: 'Random',
        is_channel: false,
        other_user: {
          first_name: 'Ana',
          last_name: 'Perez',
        } as Conversation['other_user'],
      }),
    ];
    mockUseConversations.mockReturnValue(conversations);

    const {getResult} = renderHook({searchText: ''});

    expect(getResult()).toEqual(conversations);
  });

  it('filters by group name', () => {
    const conversations = [
      createConversation({id: 'c1', name: 'Engineering'}),
      createConversation({id: 'c2', name: 'Marketing'}),
    ];
    mockUseConversations.mockReturnValue(conversations);

    const {getResult} = renderHook({searchText: 'engin'});

    expect(getResult()).toEqual([conversations[0]]);
  });

  it('filters by other user name', () => {
    const conversations = [
      createConversation({
        id: 'c1',
        is_channel: false,
        name: undefined,
        other_user: {
          first_name: 'John',
          last_name: 'Doe',
        } as Conversation['other_user'],
      }),
      createConversation({id: 'c2', name: 'General'}),
    ];
    mockUseConversations.mockReturnValue(conversations);

    const {getResult} = renderHook({searchText: 'john'});

    expect(getResult()).toEqual([conversations[0]]);
  });

  it('keeps previous conversations when frozen', () => {
    const initial = [createConversation({id: 'c1', name: 'General'})];
    const updated = [createConversation({id: 'c2', name: 'Random'})];

    mockUseConversations.mockReturnValue(initial);
    const {getResult, rerender} = renderHook({searchText: '', freeze: true});

    mockUseConversations.mockReturnValue(updated);
    rerender({searchText: 'rand', freeze: true});

    expect(getResult()).toEqual([]);
  });
});
