import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook, act } from '@testing-library/react';
import { usePlayer } from './usePlayer';
import { usePlayerStore } from '../store/playerStore';
import { audioPlayerService } from '../services/playerService';
import type { Track } from '../types';

// Mock dependencies
vi.mock('../store/playerStore', () => ({
  usePlayerStore: vi.fn(),
}));

vi.mock('../services/playerService', () => ({
  audioPlayerService: {
    initialize: vi.fn(),
    cleanup: vi.fn(),
    loadTrack: vi.fn(),
    play: vi.fn(),
    pause: vi.fn(),
    stop: vi.fn(),
    seek: vi.fn(),
    setVolume: vi.fn(),
    setMuted: vi.fn(),
    onTimeUpdate: vi.fn(),
    onDurationChange: vi.fn(),
    onEnded: vi.fn(),
    onError: vi.fn(),
    onPlay: vi.fn(),
    onPause: vi.fn(),
  },
}));

describe('usePlayer - Seek Functionality', () => {
  const mockTrack: Track = {
    id: 1,
    title: 'Test Track',
    duration: 180,
    url: 'https://example.com/track.mp3',
  };

  const mockStore = {
    currentTrack: mockTrack,
    isPlaying: true,
    currentTime: 30,
    duration: 180,
    volume: 100,
    muted: false,
    queue: [mockTrack],
    currentIndex: 0,
    repeat: 'off' as const,
    shuffle: false,
    play: vi.fn(),
    pause: vi.fn(),
    resume: vi.fn(),
    stop: vi.fn(),
    next: vi.fn(),
    previous: vi.fn(),
    seek: vi.fn(),
    setVolume: vi.fn(),
    toggleMute: vi.fn(),
    toggleShuffle: vi.fn(),
    setRepeat: vi.fn(),
    addToQueue: vi.fn(),
    clearQueue: vi.fn(),
    setCurrentTime: vi.fn(),
    setDuration: vi.fn(),
  };

  beforeEach(() => {
    vi.clearAllMocks();
    vi.mocked(usePlayerStore).mockReturnValue(mockStore as any);
  });

  it('should call store.seek and audioPlayerService.seek when seek is called', () => {
    const audioElement = document.createElement('audio');
    const audioRef = { current: audioElement };
    const { result } = renderHook(() => usePlayer(audioRef));

    act(() => {
      result.current.seek(60);
    });

    expect(mockStore.seek).toHaveBeenCalledWith(60);
    expect(audioPlayerService.seek).toHaveBeenCalledWith(60);
  });

  it('should seek to different positions', () => {
    const audioElement = document.createElement('audio');
    const audioRef = { current: audioElement };
    const { result } = renderHook(() => usePlayer(audioRef));

    act(() => {
      result.current.seek(0);
    });

    expect(mockStore.seek).toHaveBeenCalledWith(0);
    expect(audioPlayerService.seek).toHaveBeenCalledWith(0);

    act(() => {
      result.current.seek(90);
    });

    expect(mockStore.seek).toHaveBeenCalledWith(90);
    expect(audioPlayerService.seek).toHaveBeenCalledWith(90);

    act(() => {
      result.current.seek(180);
    });

    expect(mockStore.seek).toHaveBeenCalledWith(180);
    expect(audioPlayerService.seek).toHaveBeenCalledWith(180);
  });

  it('should not call audioPlayerService.seek when audioRef is null', () => {
    const { result } = renderHook(() => usePlayer(undefined));

    act(() => {
      result.current.seek(60);
    });

    expect(mockStore.seek).toHaveBeenCalledWith(60);
    // audioPlayerService.seek should not be called when audioRef is null
    expect(audioPlayerService.seek).not.toHaveBeenCalled();
  });

  it('should handle seek during playback', () => {
    const audioElement = document.createElement('audio');
    const audioRef = { current: audioElement };
    const { result } = renderHook(() => usePlayer(audioRef));

    // Simulate playing state
    vi.mocked(usePlayerStore).mockReturnValue({
      ...mockStore,
      isPlaying: true,
    } as any);

    act(() => {
      result.current.seek(45);
    });

    expect(mockStore.seek).toHaveBeenCalledWith(45);
    expect(audioPlayerService.seek).toHaveBeenCalledWith(45);
  });

  it('should handle seek when paused', () => {
    const audioElement = document.createElement('audio');
    const audioRef = { current: audioElement };
    const { result } = renderHook(() => usePlayer(audioRef));

    // Simulate paused state
    vi.mocked(usePlayerStore).mockReturnValue({
      ...mockStore,
      isPlaying: false,
    } as any);

    act(() => {
      result.current.seek(75);
    });

    expect(mockStore.seek).toHaveBeenCalledWith(75);
    expect(audioPlayerService.seek).toHaveBeenCalledWith(75);
  });

  it('should handle seek with decimal values', () => {
    const audioElement = document.createElement('audio');
    const audioRef = { current: audioElement };
    const { result } = renderHook(() => usePlayer(audioRef));

    act(() => {
      result.current.seek(45.5);
    });

    expect(mockStore.seek).toHaveBeenCalledWith(45.5);
    expect(audioPlayerService.seek).toHaveBeenCalledWith(45.5);
  });

  it('should handle seek to zero', () => {
    const audioElement = document.createElement('audio');
    const audioRef = { current: audioElement };
    const { result } = renderHook(() => usePlayer(audioRef));

    act(() => {
      result.current.seek(0);
    });

    expect(mockStore.seek).toHaveBeenCalledWith(0);
    expect(audioPlayerService.seek).toHaveBeenCalledWith(0);
  });

  it('should handle seek to end of track', () => {
    const audioElement = document.createElement('audio');
    const audioRef = { current: audioElement };
    const { result } = renderHook(() => usePlayer(audioRef));

    act(() => {
      result.current.seek(180);
    });

    expect(mockStore.seek).toHaveBeenCalledWith(180);
    expect(audioPlayerService.seek).toHaveBeenCalledWith(180);
  });
});
