// src/pages/MyDealsPage.test.tsx
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, type Mocked } from 'vitest';
import MyDealsPage from './MyDealsPage';
import * as apiClient from '../services/apiClient';
import type { WatchedItemDeal } from '../types';
import { logger } from '../services/logger.client';
import { createMockWatchedItemDeal } from '../tests/utils/mockFactories';

// The apiClient is mocked globally in `src/tests/setup/globalApiMock.ts`.
const mockedApiClient = vi.mocked(apiClient);

// Mock lucide-react icons to prevent rendering errors in the test environment
vi.mock('lucide-react', () => ({
  AlertCircle: () => <div data-testid="alert-circle-icon" />,
  Tag: () => <div data-testid="tag-icon" />,
  Store: () => <div data-testid="store-icon" />,
  Calendar: () => <div data-testid="calendar-icon" />,
}));

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

  it('should display a loading message initially', () => {
    // Mock a pending promise
    mockedApiClient.fetchBestSalePrices.mockReturnValue(new Promise(() => {}));
    render(<MyDealsPage />);
    expect(screen.getByText('Loading your deals...')).toBeInTheDocument();
  });

  it('should display an error message if the API call fails', async () => {
    mockedApiClient.fetchBestSalePrices.mockResolvedValue(
      new Response(null, { status: 500, statusText: 'Server Error' }),
    );
    render(<MyDealsPage />);

    await waitFor(() => {
      expect(screen.getByText('Error')).toBeInTheDocument();
      expect(
        screen.getByText('Failed to fetch deals. Please try again later.'),
      ).toBeInTheDocument();
    });
    expect(logger.error).toHaveBeenCalledWith(
      'Error fetching watched item deals:',
      'Failed to fetch deals. Please try again later.',
    );
  });

  it('should handle network errors and log them', async () => {
    const networkError = new Error('Network connection failed');
    mockedApiClient.fetchBestSalePrices.mockRejectedValue(networkError);
    render(<MyDealsPage />);

    await waitFor(() => {
      expect(screen.getByText('Error')).toBeInTheDocument();
      expect(screen.getByText('Network connection failed')).toBeInTheDocument();
    });
    expect(logger.error).toHaveBeenCalledWith(
      'Error fetching watched item deals:',
      'Network connection failed',
    );
  });

  it('should handle unknown errors and log them', async () => {
    // Mock a rejection with a non-Error object (e.g., a string) to trigger the fallback error message
    mockedApiClient.fetchBestSalePrices.mockRejectedValue('Unknown failure');
    render(<MyDealsPage />);

    await waitFor(() => {
      expect(screen.getByText('Error')).toBeInTheDocument();
      expect(screen.getByText('An unknown error occurred.')).toBeInTheDocument();
    });
    expect(logger.error).toHaveBeenCalledWith(
      'Error fetching watched item deals:',
      'An unknown error occurred.',
    );
  });

  it('should display a message when no deals are found', async () => {
    mockedApiClient.fetchBestSalePrices.mockResolvedValue(
      new Response(JSON.stringify([]), {
        headers: { 'Content-Type': 'application/json' },
      }),
    );
    render(<MyDealsPage />);

    await waitFor(() => {
      expect(
        screen.getByText('No deals found for your watched items right now.'),
      ).toBeInTheDocument();
    });
  });

  it('should render the list of deals on successful fetch', async () => {
    const mockDeals: WatchedItemDeal[] = [
      createMockWatchedItemDeal({
        master_item_id: 1,
        item_name: 'Organic Bananas',
        best_price_in_cents: 99,
        store_name: 'Green Grocer',
        flyer_id: 101,
        valid_to: '2024-10-20',
      }),
      createMockWatchedItemDeal({
        master_item_id: 2,
        item_name: 'Almond Milk',
        best_price_in_cents: 349,
        store_name: 'SuperMart',
        flyer_id: 102,
        valid_to: '2024-10-22',
      }),
    ];
    mockedApiClient.fetchBestSalePrices.mockResolvedValue(
      new Response(JSON.stringify(mockDeals), {
        headers: { 'Content-Type': 'application/json' },
      }),
    );

    render(<MyDealsPage />);

    await waitFor(() => {
      expect(screen.getByText('Organic Bananas')).toBeInTheDocument();
      expect(screen.getByText('$0.99')).toBeInTheDocument();
      expect(screen.getByText('Almond Milk')).toBeInTheDocument();
      expect(screen.getByText('$3.49')).toBeInTheDocument();
      expect(screen.getByText('Green Grocer')).toBeInTheDocument();
    });
  });
});
