// src/features/flyer/FlyerList.test.tsx
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, type Mocked } from 'vitest';
import { FlyerList } from './FlyerList';
import type { Flyer, UserProfile } from '../../types';
import { createMockUserProfile } from '../../tests/utils/mockFactories';
import * as apiClient from '../../services/apiClient';

// Mock the apiClient and toast notifications
vi.mock('../../services/apiClient');
vi.mock('react-hot-toast', () => ({ default: { success: vi.fn(), error: vi.fn() } }));

const mockFlyers: Flyer[] = [
  {
    flyer_id: 1,
    created_at: '2023-10-01T10:00:00Z',
    file_name: 'metro_flyer_oct_1.pdf',
    item_count: 50,
    image_url: 'http://example.com/flyer1.jpg',
    store: {
      store_id: 101,
      name: 'Metro',
      created_at: '2023-01-01T00:00:00Z',
    },
    valid_from: '2023-10-05',
    valid_to: '2023-10-11',
  },
  {
    flyer_id: 2,
    created_at: '2023-10-02T11:00:00Z',
    file_name: 'walmart_flyer.pdf',
    item_count: 75,
    image_url: 'http://example.com/flyer2.jpg',
    store: {
      store_id: 102,
      name: 'Walmart',
      created_at: '2023-01-01T00:00:00Z',
    },
    valid_from: '2023-10-06',
    valid_to: '2023-10-06', // Same day
  },
];

const mockedApiClient = apiClient as Mocked<typeof apiClient>;

describe('FlyerList', () => {
  const mockOnFlyerSelect = vi.fn();
  const mockProfile: UserProfile = createMockUserProfile({ user_id: '1', role: 'user' });

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

  it('should render the heading', () => {
    render(<FlyerList flyers={[]} onFlyerSelect={mockOnFlyerSelect} selectedFlyerId={null} profile={null} />);
    expect(screen.getByRole('heading', { name: /processed flyers/i })).toBeInTheDocument();
  });

  it('should display a message when there are no flyers', () => {
    render(<FlyerList flyers={[]} onFlyerSelect={mockOnFlyerSelect} selectedFlyerId={null} profile={null} />);
    expect(screen.getByText(/no flyers have been processed yet/i)).toBeInTheDocument();
  });

  it('should render a list of flyers with correct details', () => {
    render(<FlyerList flyers={mockFlyers} onFlyerSelect={mockOnFlyerSelect} selectedFlyerId={null} profile={mockProfile} />);

    // Check first flyer
    expect(screen.getByText('Metro')).toBeInTheDocument();
    expect(screen.getByText(/50 items/i)).toBeInTheDocument();
    expect(screen.getByText(/Valid: Oct 5 - Oct 11/i)).toBeInTheDocument();

    // Check second flyer
    expect(screen.getByText('Walmart')).toBeInTheDocument();
    expect(screen.getByText(/Valid: Oct 6/i)).toBeInTheDocument(); // Single day validity
  });

  it('should call onFlyerSelect with the correct flyer when an item is clicked', () => {
    render(<FlyerList flyers={mockFlyers} onFlyerSelect={mockOnFlyerSelect} selectedFlyerId={null} profile={mockProfile} />);

    const firstFlyerItem = screen.getByText('Metro').closest('li');
    fireEvent.click(firstFlyerItem!);

    expect(mockOnFlyerSelect).toHaveBeenCalledTimes(1);
    expect(mockOnFlyerSelect).toHaveBeenCalledWith(mockFlyers[0]);
  });

  it('should apply a selected style to the currently selected flyer', () => {
    render(<FlyerList flyers={mockFlyers} onFlyerSelect={mockOnFlyerSelect} selectedFlyerId={1} profile={mockProfile} />);

    const selectedItem = screen.getByText('Metro').closest('li');
    expect(selectedItem).toHaveClass('bg-brand-light', 'dark:bg-brand-dark/30');
  });

  describe('Admin Functionality', () => {
    const adminProfile: UserProfile = createMockUserProfile({ user_id: 'admin-1', role: 'admin' });

    it('should not show the cleanup button for non-admin users', () => {
      render(<FlyerList flyers={mockFlyers} onFlyerSelect={mockOnFlyerSelect} selectedFlyerId={null} profile={mockProfile} />);
      expect(screen.queryByTitle(/clean up files/i)).not.toBeInTheDocument();
    });

    it('should show the cleanup button for admin users', () => {
      render(<FlyerList flyers={mockFlyers} onFlyerSelect={mockOnFlyerSelect} selectedFlyerId={null} profile={adminProfile} />);
      expect(screen.getByTitle('Clean up files for flyer ID 1')).toBeInTheDocument();
      expect(screen.getByTitle('Clean up files for flyer ID 2')).toBeInTheDocument();
    });

    it('should call cleanupFlyerFiles when admin clicks and confirms', async () => {
      const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(true);
      mockedApiClient.cleanupFlyerFiles.mockResolvedValue(new Response(null, { status: 200 }));

      render(<FlyerList flyers={mockFlyers} onFlyerSelect={mockOnFlyerSelect} selectedFlyerId={null} profile={adminProfile} />);

      const cleanupButton = screen.getByTitle('Clean up files for flyer ID 1');
      fireEvent.click(cleanupButton);

      expect(confirmSpy).toHaveBeenCalledWith('Are you sure you want to clean up the files for flyer ID 1? This action cannot be undone.');
      await waitFor(() => {
        expect(mockedApiClient.cleanupFlyerFiles).toHaveBeenCalledWith(1);
      });
    });

    it('should not call cleanupFlyerFiles when admin clicks and cancels', () => {
      const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(false);

      render(<FlyerList flyers={mockFlyers} onFlyerSelect={mockOnFlyerSelect} selectedFlyerId={null} profile={adminProfile} />);

      const cleanupButton = screen.getByTitle('Clean up files for flyer ID 1');
      fireEvent.click(cleanupButton);

      expect(confirmSpy).toHaveBeenCalled();
      expect(mockedApiClient.cleanupFlyerFiles).not.toHaveBeenCalled();
    });
  });
});