// src/hooks/useFlyerSelection.test.tsx
import { renderHook, act, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import React from 'react';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { useFlyerSelection } from './useFlyerSelection';
import type { Flyer } from '../types';
import { logger } from '../services/logger.client';

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

// Create mock flyers for testing
const createMockFlyer = (id: number, storeName: string = `Store ${id}`): Flyer => ({
  flyer_id: id,
  store: {
    store_id: id,
    name: storeName,
    created_at: '2024-01-01T00:00:00Z',
    updated_at: '2024-01-01T00:00:00Z',
  },
  file_name: `flyer${id}.jpg`,
  image_url: `https://example.com/flyer${id}.jpg`,
  icon_url: `https://example.com/flyer${id}_icon.jpg`,
  status: 'processed',
  item_count: 0,
  created_at: '2024-01-01T00:00:00Z',
  updated_at: '2024-01-01T00:00:00Z',
});

const mockFlyers: Flyer[] = [
  createMockFlyer(1, 'Test Store A'),
  createMockFlyer(2, 'Test Store B'),
  createMockFlyer(3, 'Test Store C'),
];

// Wrapper component with MemoryRouter for testing route-based behavior
const createWrapper = (initialRoute: string = '/') => {
  const TestWrapper = ({ children }: { children: React.ReactNode }) => (
    <MemoryRouter initialEntries={[initialRoute]}>
      <Routes>
        <Route path="/" element={children} />
        <Route path="/flyers/:flyerId" element={children} />
      </Routes>
    </MemoryRouter>
  );
  return TestWrapper;
};

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

  describe('Initial State', () => {
    it('should initialize with null selectedFlyer', () => {
      const { result } = renderHook(() => useFlyerSelection({ flyers: [], debugLogging: false }), {
        wrapper: createWrapper('/'),
      });

      expect(result.current.selectedFlyer).toBeNull();
    });

    it('should return handleFlyerSelect as a stable function', () => {
      const { result, rerender } = renderHook(
        () => useFlyerSelection({ flyers: mockFlyers, debugLogging: false }),
        { wrapper: createWrapper('/') },
      );

      const initialHandleFlyerSelect = result.current.handleFlyerSelect;
      rerender();
      expect(result.current.handleFlyerSelect).toBe(initialHandleFlyerSelect);
    });
  });

  describe('Auto-selection', () => {
    it('should auto-select the first flyer when flyers are available and none is selected', async () => {
      const { result } = renderHook(
        () => useFlyerSelection({ flyers: mockFlyers, debugLogging: false }),
        { wrapper: createWrapper('/') },
      );

      await waitFor(() => {
        expect(result.current.selectedFlyer).toEqual(mockFlyers[0]);
      });
    });

    it('should not auto-select if flyers array is empty', () => {
      const { result } = renderHook(() => useFlyerSelection({ flyers: [], debugLogging: false }), {
        wrapper: createWrapper('/'),
      });

      expect(result.current.selectedFlyer).toBeNull();
    });

    it('should log debug message when auto-selecting in test mode', async () => {
      renderHook(() => useFlyerSelection({ flyers: mockFlyers, debugLogging: true }), {
        wrapper: createWrapper('/'),
      });

      await waitFor(() => {
        expect(logger.debug).toHaveBeenCalledWith('[useFlyerSelection] Auto-selecting first flyer');
      });
    });
  });

  describe('Manual Selection', () => {
    it('should update selectedFlyer when handleFlyerSelect is called', async () => {
      const { result } = renderHook(
        () => useFlyerSelection({ flyers: mockFlyers, debugLogging: false }),
        { wrapper: createWrapper('/') },
      );

      // Wait for auto-selection first
      await waitFor(() => {
        expect(result.current.selectedFlyer).toBeTruthy();
      });

      // Manually select a different flyer
      act(() => {
        result.current.handleFlyerSelect(mockFlyers[2]);
      });

      expect(result.current.selectedFlyer).toEqual(mockFlyers[2]);
    });
  });

  describe('URL-based Selection', () => {
    it('should select flyer based on flyerId from URL', async () => {
      const { result } = renderHook(
        () => useFlyerSelection({ flyers: mockFlyers, debugLogging: false }),
        { wrapper: createWrapper('/flyers/2') },
      );

      await waitFor(() => {
        expect(result.current.selectedFlyer?.flyer_id).toBe(2);
      });
    });

    it('should extract flyerIdFromUrl from the URL path', () => {
      const { result } = renderHook(
        () => useFlyerSelection({ flyers: mockFlyers, debugLogging: false }),
        { wrapper: createWrapper('/flyers/3') },
      );

      expect(result.current.flyerIdFromUrl).toBe('3');
    });

    it('should return undefined flyerIdFromUrl when not on a flyer route', () => {
      const { result } = renderHook(
        () => useFlyerSelection({ flyers: mockFlyers, debugLogging: false }),
        { wrapper: createWrapper('/') },
      );

      expect(result.current.flyerIdFromUrl).toBeUndefined();
    });

    it('should fall back to first flyer when flyerId from URL does not exist', async () => {
      const { result } = renderHook(
        () => useFlyerSelection({ flyers: mockFlyers, debugLogging: false }),
        { wrapper: createWrapper('/flyers/999') },
      );

      // Should auto-select first flyer since flyerId 999 doesn't exist
      await waitFor(() => {
        expect(result.current.selectedFlyer?.flyer_id).toBe(1);
      });
    });

    it('should log debug message when selecting from URL', async () => {
      renderHook(() => useFlyerSelection({ flyers: mockFlyers, debugLogging: true }), {
        wrapper: createWrapper('/flyers/2'),
      });

      await waitFor(() => {
        expect(logger.debug).toHaveBeenCalledWith(
          { flyerId: 2, flyerToSelect: 2 },
          '[useFlyerSelection] Selecting flyer from URL',
        );
      });
    });
  });

  describe('Debug Logging', () => {
    it('should not log when debugLogging is false', async () => {
      renderHook(() => useFlyerSelection({ flyers: mockFlyers, debugLogging: false }), {
        wrapper: createWrapper('/'),
      });

      await waitFor(() => {
        // Allow time for any potential logging
      });

      expect(logger.debug).not.toHaveBeenCalled();
    });

    it('should use NODE_ENV for default debugLogging behavior', () => {
      // The default is debugLogging = process.env.NODE_ENV === 'test'
      // In our test environment, NODE_ENV is 'test', so it should log
      renderHook(
        () => useFlyerSelection({ flyers: mockFlyers }), // No debugLogging specified
        { wrapper: createWrapper('/') },
      );

      // Since NODE_ENV === 'test' and we didn't override debugLogging,
      // it should default to true and log
    });
  });
});
