// src/hooks/useDataExtraction.test.ts
import { renderHook, act } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
import { useDataExtraction } from './useDataExtraction';
import type { Flyer } from '../types';

// Create a mock flyer 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',
});

describe('useDataExtraction Hook', () => {
  let mockOnFlyerUpdate: Mock<(flyer: Flyer) => void>;

  beforeEach(() => {
    mockOnFlyerUpdate = vi.fn();
  });

  describe('Initial State', () => {
    it('should return handleDataExtracted as a function', () => {
      const mockFlyer = createMockFlyer(1);
      const { result } = renderHook(() =>
        useDataExtraction({
          selectedFlyer: mockFlyer,
          onFlyerUpdate: mockOnFlyerUpdate,
        }),
      );

      expect(typeof result.current.handleDataExtracted).toBe('function');
    });

    it('should maintain stable function reference across re-renders when dependencies are unchanged', () => {
      const mockFlyer = createMockFlyer(1);
      const { result, rerender } = renderHook(() =>
        useDataExtraction({
          selectedFlyer: mockFlyer,
          onFlyerUpdate: mockOnFlyerUpdate,
        }),
      );

      const initialHandler = result.current.handleDataExtracted;
      rerender();
      expect(result.current.handleDataExtracted).toBe(initialHandler);
    });
  });

  describe('Store Name Extraction', () => {
    it('should update store name when type is store_name', () => {
      const mockFlyer = createMockFlyer(1, 'Original Store');
      const { result } = renderHook(() =>
        useDataExtraction({
          selectedFlyer: mockFlyer,
          onFlyerUpdate: mockOnFlyerUpdate,
        }),
      );

      act(() => {
        result.current.handleDataExtracted('store_name', 'New Store Name');
      });

      expect(mockOnFlyerUpdate).toHaveBeenCalledTimes(1);
      const updatedFlyer = mockOnFlyerUpdate.mock.calls[0][0];
      expect(updatedFlyer.store?.name).toBe('New Store Name');
      // Ensure other properties are preserved
      expect(updatedFlyer.flyer_id).toBe(1);
      expect(updatedFlyer.image_url).toBe('https://example.com/flyer1.jpg');
    });

    it('should preserve store_id when updating store name', () => {
      const mockFlyer = createMockFlyer(42, 'Original Store');
      const { result } = renderHook(() =>
        useDataExtraction({
          selectedFlyer: mockFlyer,
          onFlyerUpdate: mockOnFlyerUpdate,
        }),
      );

      act(() => {
        result.current.handleDataExtracted('store_name', 'Updated Store');
      });

      const updatedFlyer = mockOnFlyerUpdate.mock.calls[0][0];
      expect(updatedFlyer.store?.store_id).toBe(42);
    });
  });

  describe('Date Extraction', () => {
    it('should call onFlyerUpdate when type is dates', () => {
      const mockFlyer = createMockFlyer(1);
      const { result } = renderHook(() =>
        useDataExtraction({
          selectedFlyer: mockFlyer,
          onFlyerUpdate: mockOnFlyerUpdate,
        }),
      );

      act(() => {
        result.current.handleDataExtracted('dates', '2024-01-15 - 2024-01-21');
      });

      // The hook is called but date parsing is not implemented yet
      // It should still call onFlyerUpdate with the unchanged flyer
      expect(mockOnFlyerUpdate).toHaveBeenCalledTimes(1);
    });
  });

  describe('Null Flyer Handling', () => {
    it('should not call onFlyerUpdate when selectedFlyer is null', () => {
      const { result } = renderHook(() =>
        useDataExtraction({
          selectedFlyer: null,
          onFlyerUpdate: mockOnFlyerUpdate,
        }),
      );

      act(() => {
        result.current.handleDataExtracted('store_name', 'New Store');
      });

      expect(mockOnFlyerUpdate).not.toHaveBeenCalled();
    });

    it('should not throw when selectedFlyer is null', () => {
      const { result } = renderHook(() =>
        useDataExtraction({
          selectedFlyer: null,
          onFlyerUpdate: mockOnFlyerUpdate,
        }),
      );

      expect(() => {
        act(() => {
          result.current.handleDataExtracted('store_name', 'New Store');
        });
      }).not.toThrow();
    });
  });

  describe('Callback Stability', () => {
    it('should update handler when selectedFlyer changes', () => {
      const mockFlyer1 = createMockFlyer(1, 'Store 1');
      const mockFlyer2 = createMockFlyer(2, 'Store 2');

      const { result, rerender } = renderHook(
        ({ selectedFlyer }) =>
          useDataExtraction({
            selectedFlyer,
            onFlyerUpdate: mockOnFlyerUpdate,
          }),
        { initialProps: { selectedFlyer: mockFlyer1 } },
      );

      const handler1 = result.current.handleDataExtracted;

      rerender({ selectedFlyer: mockFlyer2 });

      const handler2 = result.current.handleDataExtracted;

      // Handler should be different since selectedFlyer changed
      expect(handler1).not.toBe(handler2);
    });

    it('should update handler when onFlyerUpdate changes', () => {
      const mockFlyer = createMockFlyer(1);
      const mockOnFlyerUpdate2: Mock<(flyer: Flyer) => void> = vi.fn();

      const { result, rerender } = renderHook(
        ({ onFlyerUpdate }) =>
          useDataExtraction({
            selectedFlyer: mockFlyer,
            onFlyerUpdate,
          }),
        { initialProps: { onFlyerUpdate: mockOnFlyerUpdate } },
      );

      const handler1 = result.current.handleDataExtracted;

      rerender({ onFlyerUpdate: mockOnFlyerUpdate2 });

      const handler2 = result.current.handleDataExtracted;

      // Handler should be different since onFlyerUpdate changed
      expect(handler1).not.toBe(handler2);
    });
  });
});
