// src/features/flyer/AnalysisPanel.test.tsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from 'vitest';
import { AnalysisPanel } from './AnalysisPanel';
import { useFlyerItems } from '../../hooks/useFlyerItems';
import type { Flyer, FlyerItem, Store, MasterGroceryItem } from '../../types';
import { useUserData } from '../../hooks/useUserData';
import { useAiAnalysis } from '../../hooks/useAiAnalysis';
import {
  createMockFlyer,
  createMockFlyerItem,
  createMockMasterGroceryItem,
  createMockStore,
} from '../../tests/utils/mockFactories';

// Mock the logger
vi.mock('../../services/logger.client', () => ({
  logger: { info: vi.fn(), error: vi.fn() },
}));

// Mock the AiAnalysisService to prevent real instantiation
vi.mock('../../services/aiAnalysisService', () => {
  console.log('DEBUG: Setting up AiAnalysisService mock');
  return {
    AiAnalysisService: class {
      constructor() {
        console.log('DEBUG: AiAnalysisService constructor mocked call');
      }
    },
  };
});

// Mock the data hooks
vi.mock('../../hooks/useFlyerItems');
const mockedUseFlyerItems = useFlyerItems as Mock;
vi.mock('../../hooks/useUserData');
const mockedUseUserData = useUserData as Mock;
vi.mock('../../hooks/useAiAnalysis');
const mockedUseAiAnalysis = useAiAnalysis as Mock;

// Mock the new icon
vi.mock('../../components/icons/ScaleIcon', () => ({
  ScaleIcon: () => <div data-testid="scale-icon" />,
}));

// Mock functions to be returned by the useAiAnalysis hook
const mockRunAnalysis = vi.fn();
const mockGenerateImage = vi.fn();

const mockFlyerItems: FlyerItem[] = [
  createMockFlyerItem({
    flyer_item_id: 1,
    item: 'Apples',
    price_display: '$1.99',
    price_in_cents: 199,
    quantity: '1lb',
    flyer_id: 1,
  }),
];

const mockWatchedItems: MasterGroceryItem[] = [
  createMockMasterGroceryItem({ master_grocery_item_id: 101, name: 'Bananas' }),
  createMockMasterGroceryItem({ master_grocery_item_id: 102, name: 'Milk' }),
];

const mockStore: Store = createMockStore({ store_id: 1, name: 'SuperMart' });

const mockFlyer: Flyer = createMockFlyer({
  flyer_id: 1,
  store: mockStore,
});

describe('AnalysisPanel', () => {
  beforeEach(() => {
    console.log('DEBUG: beforeEach setup start');
    vi.clearAllMocks();
    mockedUseFlyerItems.mockReturnValue({
      flyerItems: mockFlyerItems,
      isLoading: false,
      error: null,
    });
    mockedUseUserData.mockReturnValue({
      watchedItems: mockWatchedItems,
      isLoading: false,
      error: null,
    });
    mockedUseAiAnalysis.mockReturnValue({
      results: {},
      sources: {},
      loadingAnalysis: null,
      error: null,
      runAnalysis: mockRunAnalysis,
      generatedImageUrl: null,
      generateImage: mockGenerateImage,
    });

    console.log('DEBUG: beforeEach setup complete');
  });

  afterEach(() => {
    console.log('DEBUG: afterEach - cleaning up');
    vi.clearAllMocks();
  });

  // Increased timeout to 20s to prevent flaky timeouts in slow environments
  it('should render tabs and an initial "Generate" button', { timeout: 20000 }, () => {
    console.log('DEBUG: Starting render for initial state test');
    const startTime = Date.now();
    render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    console.log(`DEBUG: Render finished in ${Date.now() - startTime}ms`);

    // Use the 'tab' role to specifically target the tab buttons
    console.log('DEBUG: Asserting tab existence');
    expect(screen.getByRole('tab', { name: /quick insights/i })).toBeInTheDocument();
    expect(screen.getByRole('tab', { name: /deep dive/i })).toBeInTheDocument();
    expect(screen.getByRole('tab', { name: /web search/i })).toBeInTheDocument();
    expect(screen.getByRole('tab', { name: /plan trip/i })).toBeInTheDocument();
    expect(screen.getByRole('tab', { name: /compare prices/i })).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /generate quick insights/i })).toBeInTheDocument();
    console.log('DEBUG: Initial state test complete');
  });

  it('should switch tabs and update the generate button text', () => {
    render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    fireEvent.click(screen.getByRole('tab', { name: /deep dive/i }));
    expect(screen.getByRole('button', { name: /generate deep dive/i })).toBeInTheDocument();
    fireEvent.click(screen.getByRole('tab', { name: /compare prices/i }));
    expect(screen.getByRole('button', { name: /generate compare prices/i })).toBeInTheDocument();
  });

  it('should call getQuickInsights and display the result', async () => {
    const { rerender } = render(<AnalysisPanel selectedFlyer={mockFlyer} />);

    fireEvent.click(screen.getByRole('button', { name: /generate quick insights/i }));

    expect(mockRunAnalysis).toHaveBeenCalledWith('QUICK_INSIGHTS');

    // Simulate the hook updating with results
    mockedUseAiAnalysis.mockReturnValue({
      results: { QUICK_INSIGHTS: 'These are quick insights.' },
      sources: {},
      loadingAnalysis: null,
      error: null,
      runAnalysis: mockRunAnalysis,
      generatedImageUrl: null,
      generateImage: mockGenerateImage,
    });

    rerender(<AnalysisPanel selectedFlyer={mockFlyer} />);

    expect(screen.getByText('These are quick insights.')).toBeInTheDocument();
  });

  it('should display results with sources, and handle sources without a URI', () => {
    const { rerender } = render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    fireEvent.click(screen.getByRole('tab', { name: /web search/i }));

    mockedUseAiAnalysis.mockReturnValue({
      results: { WEB_SEARCH: 'Search results text.' },
      sources: {
        WEB_SEARCH: [
          { title: 'Valid Source', uri: 'https://example.com/source1' },
          { title: 'Source without URI', uri: null },
          { title: 'Another Valid Source', uri: 'https://example.com/source2' },
        ],
      },
      loadingAnalysis: null,
      error: null,
      runAnalysis: mockRunAnalysis,
      generatedImageUrl: null,
      generateImage: mockGenerateImage,
    });

    rerender(<AnalysisPanel selectedFlyer={mockFlyer} />);

    expect(screen.getByText('Search results text.')).toBeInTheDocument();
    expect(screen.getByText('Sources:')).toBeInTheDocument();
    const source1 = screen.getByText('Valid Source');
    expect(source1).toBeInTheDocument();
    expect(source1.closest('a')).toHaveAttribute('href', 'https://example.com/source1');
    expect(screen.queryByText('Source without URI')).not.toBeInTheDocument();
    expect(screen.getByText('Another Valid Source')).toBeInTheDocument();
  });

  it('should show a loading spinner when fetching initial items', () => {
    mockedUseFlyerItems.mockReturnValue({
      flyerItems: [],
      isLoading: true,
      error: null,
    });
    render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    expect(screen.getByRole('status')).toBeInTheDocument();
    expect(screen.getByText('Loading data...')).toBeInTheDocument();
  });

  it('should show an error if fetching items fails', () => {
    mockedUseFlyerItems.mockReturnValue({
      flyerItems: [],
      isLoading: false,
      error: new Error('Network Error'),
    });
    render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    expect(screen.getByText('Could not load flyer items: Network Error')).toBeInTheDocument();
  });

  it('should show a loading spinner during analysis', () => {
    mockedUseAiAnalysis.mockReturnValue({
      ...mockedUseAiAnalysis(),
      loadingAnalysis: 'QUICK_INSIGHTS',
    });
    render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    expect(screen.getByRole('status')).toBeInTheDocument();
    // The simple spinner doesn't have text next to it
    expect(screen.queryByText('Loading data...')).not.toBeInTheDocument();
  });

  it('should display an error message if analysis fails', async () => {
    const { rerender } = render(<AnalysisPanel selectedFlyer={mockFlyer} />);

    fireEvent.click(screen.getByRole('button', { name: /generate quick insights/i }));

    // Simulate the hook returning an error
    mockedUseAiAnalysis.mockReturnValue({
      results: {},
      sources: {},
      loadingAnalysis: null,
      error: 'AI API is down',
      runAnalysis: mockRunAnalysis,
      generatedImageUrl: null,
      generateImage: mockGenerateImage,
    });

    rerender(<AnalysisPanel selectedFlyer={mockFlyer} />);

    expect(screen.getByText('AI API is down')).toBeInTheDocument();
  });

  it('should handle the image generation flow', async () => {
    const { rerender } = render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    fireEvent.click(screen.getByRole('tab', { name: /deep dive/i }));

    // 1. Show result and "Generate Image" button
    mockedUseAiAnalysis.mockReturnValue({
      results: { DEEP_DIVE: 'This is a meal plan.' },
      sources: {},
      loadingAnalysis: null,
      error: null,
      runAnalysis: mockRunAnalysis,
      generatedImageUrl: null,
      generateImage: mockGenerateImage,
    });
    rerender(<AnalysisPanel selectedFlyer={mockFlyer} />);
    const generateImageButton = screen.getByRole('button', { name: /generate an image/i });
    expect(generateImageButton).toBeInTheDocument();

    // 2. Click button, show loading state
    fireEvent.click(generateImageButton);
    expect(mockGenerateImage).toHaveBeenCalled();

    mockedUseAiAnalysis.mockReturnValue({
      results: { DEEP_DIVE: 'This is a meal plan.' },
      sources: {},
      loadingAnalysis: 'GENERATE_IMAGE',
      error: null,
      runAnalysis: mockRunAnalysis,
      generatedImageUrl: null,
      generateImage: mockGenerateImage,
    });
    rerender(<AnalysisPanel selectedFlyer={mockFlyer} />);
    expect(screen.getByRole('button', { name: /generating/i })).toBeDisabled();
    expect(screen.getByText('Generating...')).toBeInTheDocument();

    // 3. Show the generated image
    mockedUseAiAnalysis.mockReturnValue({
      results: { DEEP_DIVE: 'This is a meal plan.' },
      sources: {},
      loadingAnalysis: null,
      error: null,
      runAnalysis: mockRunAnalysis,
      generatedImageUrl: 'https://example.com/meal.jpg',
      generateImage: mockGenerateImage,
    });
    rerender(<AnalysisPanel selectedFlyer={mockFlyer} />);
    const image = screen.getByAltText('AI generated meal plan');
    expect(image).toBeInTheDocument();
    expect(image).toHaveAttribute('src', 'https://example.com/meal.jpg');
  });

  it('should not show sources for non-search analysis types', () => {
    mockedUseAiAnalysis.mockReturnValue({
      results: { QUICK_INSIGHTS: 'Some insights.' },
      sources: { QUICK_INSIGHTS: [{ title: 'A source', uri: 'http://a.com' }] },
      loadingAnalysis: null,
      error: null,
      runAnalysis: mockRunAnalysis,
      generatedImageUrl: null,
      generateImage: mockGenerateImage,
    });
    render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    expect(screen.getByText('Some insights.')).toBeInTheDocument();
    expect(screen.queryByText('Sources:')).not.toBeInTheDocument();
  });

  it('should display sources for Plan Trip analysis type', () => {
    const { rerender } = render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    fireEvent.click(screen.getByRole('tab', { name: /plan trip/i }));

    mockedUseAiAnalysis.mockReturnValue({
      results: { PLAN_TRIP: 'Here is your trip plan.' },
      sources: {
        PLAN_TRIP: [{ title: 'Store Location', uri: 'https://maps.example.com/store1' }],
      },
      loadingAnalysis: null,
      error: null,
      runAnalysis: mockRunAnalysis,
      generatedImageUrl: null,
      generateImage: mockGenerateImage,
    });

    rerender(<AnalysisPanel selectedFlyer={mockFlyer} />);

    expect(screen.getByText('Here is your trip plan.')).toBeInTheDocument();
    expect(screen.getByText('Sources:')).toBeInTheDocument();
    expect(screen.getByText('Store Location')).toBeInTheDocument();
  });

  it('should display sources for Compare Prices analysis type', () => {
    const { rerender } = render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    fireEvent.click(screen.getByRole('tab', { name: /compare prices/i }));

    mockedUseAiAnalysis.mockReturnValue({
      results: { COMPARE_PRICES: 'Price comparison results.' },
      sources: {
        COMPARE_PRICES: [{ title: 'Price Source', uri: 'https://prices.example.com/compare' }],
      },
      loadingAnalysis: null,
      error: null,
      runAnalysis: mockRunAnalysis,
      generatedImageUrl: null,
      generateImage: mockGenerateImage,
    });

    rerender(<AnalysisPanel selectedFlyer={mockFlyer} />);

    expect(screen.getByText('Price comparison results.')).toBeInTheDocument();
    expect(screen.getByText('Sources:')).toBeInTheDocument();
    expect(screen.getByText('Price Source')).toBeInTheDocument();
  });

  it('should show a loading spinner when loading watched items', () => {
    mockedUseUserData.mockReturnValue({
      watchedItems: [],
      isLoading: true,
      error: null,
    });
    render(<AnalysisPanel selectedFlyer={mockFlyer} />);
    expect(screen.getByRole('status')).toBeInTheDocument();
    expect(screen.getByText('Loading data...')).toBeInTheDocument();
  });
});
