import React from 'react';

import type { PayeeEntity } from '@actual-app/core/types/models';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { useNavigate } from '#hooks/useNavigate';
import { createTestQueryClient, TestProviders } from '#mocks';
import { payeeQueries } from '#payees';

import { MobilePayeesPage } from './MobilePayeesPage';

vi.mock('@use-gesture/react', () => ({
  useDrag: vi.fn().mockReturnValue(() => ({})),
}));
vi.mock('#hooks/useNavigate');

const mockPayees: PayeeEntity[] = [
  {
    id: 'payee-1',
    name: 'Grocery Store',
    favorite: false,
  },
  {
    id: 'payee-2',
    name: 'Gas Station',
    favorite: true,
  },
  {
    id: 'payee-3',
    name: 'Restaurant',
    favorite: false,
  },
];

describe('MobilePayeesPage', () => {
  const mockNavigate = vi.fn();
  const queryClient = createTestQueryClient();

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

    vi.mocked(useNavigate).mockReturnValue(mockNavigate);

    queryClient.setQueryData(payeeQueries.list().queryKey, mockPayees);
    queryClient.setQueryData(
      payeeQueries.ruleCounts().queryKey,
      new Map([
        ['payee-1', 2],
        ['payee-2', 0],
      ]),
    );
  });

  const renderPayeesPage = () => {
    return render(
      <TestProviders queryClient={queryClient}>
        <MobilePayeesPage />
      </TestProviders>,
    );
  };

  it('renders payees page with header', () => {
    renderPayeesPage();

    expect(
      screen.getByRole('heading', { name: /payees/i }),
    ).toBeInTheDocument();
  });

  it('renders search box', () => {
    renderPayeesPage();

    const searchBox = screen.getByPlaceholderText(/filter payees/i);
    expect(searchBox).toBeInTheDocument();
  });

  it('displays all payees when no filter is applied', () => {
    renderPayeesPage();

    // All payees should be visible
    expect(screen.getByText('Grocery Store')).toBeInTheDocument();
    expect(screen.getByText('Gas Station')).toBeInTheDocument();
    expect(screen.getByText('Restaurant')).toBeInTheDocument();
  });

  it('filters payees by search term', async () => {
    const user = userEvent.setup();
    renderPayeesPage();

    const searchBox = screen.getByPlaceholderText(/filter payees/i);

    await user.type(searchBox, 'Grocery');

    // Only matching payee should be visible
    expect(screen.getByText('Grocery Store')).toBeInTheDocument();
    expect(screen.queryByText('Gas Station')).not.toBeInTheDocument();
    expect(screen.queryByText('Restaurant')).not.toBeInTheDocument();
  });

  it('filters payees case-insensitively', async () => {
    const user = userEvent.setup();
    renderPayeesPage();

    const searchBox = screen.getByPlaceholderText(/filter payees/i);

    await user.type(searchBox, 'gas');

    // Should find "Gas Station" regardless of case
    expect(screen.getByText('Gas Station')).toBeInTheDocument();
    expect(screen.queryByText('Grocery Store')).not.toBeInTheDocument();
  });

  it('clears filter when search is cleared', async () => {
    const user = userEvent.setup();
    renderPayeesPage();

    const searchBox = screen.getByPlaceholderText(/filter payees/i);

    await user.type(searchBox, 'Grocery');
    expect(screen.queryByText('Gas Station')).not.toBeInTheDocument();

    await user.clear(searchBox);

    // All payees should be visible again
    expect(screen.getByText('Grocery Store')).toBeInTheDocument();
    expect(screen.getByText('Gas Station')).toBeInTheDocument();
    expect(screen.getByText('Restaurant')).toBeInTheDocument();
  });

  it('navigates to payee edit page when payee is clicked', async () => {
    const user = userEvent.setup();
    renderPayeesPage();

    const payeeButton = screen.getByText('Grocery Store');
    await user.click(payeeButton);

    expect(mockNavigate).toBeCalledWith('/payees/payee-1');
  });

  it('shows empty state when no payees match filter', async () => {
    const user = userEvent.setup();
    renderPayeesPage();

    const searchBox = screen.getByPlaceholderText(/filter payees/i);

    await user.type(searchBox, 'NonexistentPayee123');

    // No payees should match
    expect(screen.queryByText('Grocery Store')).not.toBeInTheDocument();
    expect(screen.queryByText('Gas Station')).not.toBeInTheDocument();
    expect(screen.queryByText('Restaurant')).not.toBeInTheDocument();
  });

  it('handles empty payee list', () => {
    // Set empty payee list in the cache
    queryClient.setQueryData(payeeQueries.list().queryKey, []);
    queryClient.setQueryData(payeeQueries.ruleCounts().queryKey, new Map());

    renderPayeesPage();

    // Page should render even with no payees
    expect(
      screen.getByRole('heading', { name: /payees/i }),
    ).toBeInTheDocument();
    expect(screen.getByPlaceholderText(/filter payees/i)).toBeInTheDocument();
  });
});
