// src/pages/admin/CorrectionsPage.test.tsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { MemoryRouter } from 'react-router-dom';
import { CorrectionsPage } from './CorrectionsPage';
import { useSuggestedCorrectionsQuery } from '../../hooks/queries/useSuggestedCorrectionsQuery';
import { useMasterItemsQuery } from '../../hooks/queries/useMasterItemsQuery';
import { useCategoriesQuery } from '../../hooks/queries/useCategoriesQuery';
import type { SuggestedCorrection, MasterGroceryItem, Category } from '../../types';
import {
  createMockSuggestedCorrection,
  createMockMasterGroceryItem,
  createMockCategory,
} from '../../tests/utils/mockFactories';
import { QueryWrapper } from '../../tests/utils/renderWithProviders';

// Mock the TanStack Query hooks
vi.mock('../../hooks/queries/useSuggestedCorrectionsQuery');
vi.mock('../../hooks/queries/useMasterItemsQuery');
vi.mock('../../hooks/queries/useCategoriesQuery');

const mockedUseSuggestedCorrectionsQuery = vi.mocked(useSuggestedCorrectionsQuery);
const mockedUseMasterItemsQuery = vi.mocked(useMasterItemsQuery);
const mockedUseCategoriesQuery = vi.mocked(useCategoriesQuery);

// Mock the child CorrectionRow component to isolate the test to the page itself
vi.mock('./components/CorrectionRow', async () => {
  const { MockCorrectionRow } = await import('../../tests/utils/componentMocks');
  return { CorrectionRow: MockCorrectionRow };
});

// Helper to render the component within router and query contexts
const renderWithRouter = () => {
  return render(
    <QueryWrapper>
      <MemoryRouter>
        <CorrectionsPage />
      </MemoryRouter>
    </QueryWrapper>,
  );
};

describe('CorrectionsPage', () => {
  const mockCorrections: SuggestedCorrection[] = [
    createMockSuggestedCorrection({
      suggested_correction_id: 1,
      flyer_item_id: 101,
      user_id: 'user-1',
      correction_type: 'item_name',
      suggested_value: 'Organic Bananas',
      flyer_item_name: 'Bananas',
      user_email: 'test@example.com',
    }),
    createMockSuggestedCorrection({
      suggested_correction_id: 2,
      flyer_item_id: 102,
      user_id: 'user-2',
      correction_type: 'price_in_cents',
      suggested_value: '199',
      flyer_item_name: 'Apples',
      user_email: 'test2@example.com',
    }),
  ];
  const mockMasterItems: MasterGroceryItem[] = [
    createMockMasterGroceryItem({
      master_grocery_item_id: 1,
      name: 'Organic Bananas',
      category_id: 1,
      category_name: 'Produce',
    }),
  ];
  const mockCategories: Category[] = [createMockCategory({ category_id: 1, name: 'Produce' })];
  const mockRefetch = vi.fn();

  beforeEach(() => {
    vi.clearAllMocks();
    // Default mock implementations for the hooks
    mockedUseSuggestedCorrectionsQuery.mockReturnValue({
      data: [],
      isLoading: false,
      error: null,
      refetch: mockRefetch,
    } as any);
    mockedUseMasterItemsQuery.mockReturnValue({
      data: [],
      isLoading: false,
      error: null,
    } as any);
    mockedUseCategoriesQuery.mockReturnValue({
      data: [],
      isLoading: false,
      error: null,
    } as any);
  });

  it('should render a loading spinner while fetching data', async () => {
    mockedUseSuggestedCorrectionsQuery.mockReturnValue({
      data: undefined,
      isLoading: true,
      error: null,
      refetch: mockRefetch,
    } as any);

    renderWithRouter();

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

  it('should display corrections when data is fetched successfully', async () => {
    mockedUseSuggestedCorrectionsQuery.mockReturnValue({
      data: mockCorrections,
      isLoading: false,
      error: null,
      refetch: mockRefetch,
    } as any);
    mockedUseMasterItemsQuery.mockReturnValue({
      data: mockMasterItems,
      isLoading: false,
      error: null,
    } as any);
    mockedUseCategoriesQuery.mockReturnValue({
      data: mockCategories,
      isLoading: false,
      error: null,
    } as any);

    renderWithRouter();

    // Check for the mocked CorrectionRow components
    expect(screen.getByTestId('correction-row-1')).toBeInTheDocument();
    expect(screen.getByTestId('correction-row-2')).toBeInTheDocument();
    // Check for the text content within the mocked rows
    expect(screen.getByText('Bananas')).toBeInTheDocument();
    expect(screen.getByText('Apples')).toBeInTheDocument();
  });

  it('should display a message when there are no pending corrections', async () => {
    mockedUseSuggestedCorrectionsQuery.mockReturnValue({
      data: [],
      isLoading: false,
      error: null,
      refetch: mockRefetch,
    } as any);
    mockedUseMasterItemsQuery.mockReturnValue({
      data: mockMasterItems,
      isLoading: false,
      error: null,
    } as any);
    mockedUseCategoriesQuery.mockReturnValue({
      data: mockCategories,
      isLoading: false,
      error: null,
    } as any);

    renderWithRouter();

    expect(screen.getByText(/no pending corrections. great job!/i)).toBeInTheDocument();
  });

  it('should display an error message if fetching corrections fails', async () => {
    const errorMessage = 'Network Error: Failed to fetch';
    mockedUseSuggestedCorrectionsQuery.mockReturnValue({
      data: undefined,
      isLoading: false,
      error: new Error(errorMessage),
      refetch: mockRefetch,
    } as any);
    mockedUseMasterItemsQuery.mockReturnValue({
      data: mockMasterItems,
      isLoading: false,
      error: null,
    } as any);
    mockedUseCategoriesQuery.mockReturnValue({
      data: mockCategories,
      isLoading: false,
      error: null,
    } as any);

    renderWithRouter();

    expect(screen.getByText(errorMessage)).toBeInTheDocument();
  });

  it('should call refetch when the refresh button is clicked', async () => {
    mockedUseSuggestedCorrectionsQuery.mockReturnValue({
      data: mockCorrections,
      isLoading: false,
      error: null,
      refetch: mockRefetch,
    } as any);
    mockedUseMasterItemsQuery.mockReturnValue({
      data: mockMasterItems,
      isLoading: false,
      error: null,
    } as any);
    mockedUseCategoriesQuery.mockReturnValue({
      data: mockCategories,
      isLoading: false,
      error: null,
    } as any);

    renderWithRouter();
    expect(screen.getByText('Bananas')).toBeInTheDocument();

    // Click refresh
    const refreshButton = screen.getByTitle('Refresh Corrections');
    fireEvent.click(refreshButton);

    expect(mockRefetch).toHaveBeenCalledTimes(1);
  });

  it('should call onProcessed callback when a correction is processed', async () => {
    mockedUseSuggestedCorrectionsQuery.mockReturnValue({
      data: mockCorrections,
      isLoading: false,
      error: null,
      refetch: mockRefetch,
    } as any);
    mockedUseMasterItemsQuery.mockReturnValue({
      data: mockMasterItems,
      isLoading: false,
      error: null,
    } as any);
    mockedUseCategoriesQuery.mockReturnValue({
      data: mockCategories,
      isLoading: false,
      error: null,
    } as any);

    renderWithRouter();
    expect(screen.getByTestId('correction-row-1')).toBeInTheDocument();

    // Click the process button in the mock row for ID 1
    fireEvent.click(screen.getByTestId('process-btn-1'));

    // The onProcessed callback should trigger a refetch
    expect(mockRefetch).toHaveBeenCalledTimes(1);
  });
});
