import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { trackService } from '../trackService';
import { api, API_URL } from '../api';

// Mock the api module
vi.mock('../api', () => ({
  api: {
    get: vi.fn(),
    post: vi.fn(),
    put: vi.fn(),
    delete: vi.fn(),
  },
  API_URL: 'http://localhost:8080/api/v1',
}));

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

  afterEach(() => {
    vi.restoreAllMocks();
  });

  describe('list', () => {
    it('should list tracks with default params', async () => {
      const mockTracks = [
        {
          id: '1',
          title: 'Test Track',
          artist: 'Test Artist',
          album: 'Test Album',
          duration: 180,
          play_count: 100,
          like_count: 50,
          genre: 'Electronic',
          status: 'completed',
          created_at: '2024-01-01T00:00:00Z',
        },
      ];

      vi.mocked(api.get).mockResolvedValue({ data: mockTracks });

      const result = await trackService.list();

      expect(api.get).toHaveBeenCalledWith('/tracks', undefined);
      expect(result.tracks).toHaveLength(1);
      expect(result.tracks[0].title).toBe('Test Track');
      expect(result.tracks[0].duration).toBe('3:00');
    });

    it('should list tracks with pagination params', async () => {
      const mockTracks = [];
      vi.mocked(api.get).mockResolvedValue({
        data: mockTracks,
        meta: { page: 1, limit: 20 },
      });

      const result = await trackService.list({ page: 1, limit: 20 });

      expect(api.get).toHaveBeenCalledWith('/tracks', { page: 1, limit: 20 });
      expect(result.pagination).toEqual({ page: 1, limit: 20 });
    });

    it('should list tracks with filters', async () => {
      const mockTracks = [];
      vi.mocked(api.get).mockResolvedValue({ data: mockTracks });

      await trackService.list({ user_id: '123', genre: 'Electronic' });

      expect(api.get).toHaveBeenCalledWith('/tracks', {
        user_id: '123',
        genre: 'Electronic',
      });
    });

    it('should handle array response format', async () => {
      const mockTracks = [
        {
          id: '1',
          title: 'Test Track',
          artist: 'Test Artist',
          duration: 180,
          play_count: 0,
          like_count: 0,
          genre: 'Electronic',
          status: 'completed',
          created_at: '2024-01-01T00:00:00Z',
        },
      ];

      vi.mocked(api.get).mockResolvedValue(mockTracks);

      const result = await trackService.list();

      expect(result.tracks).toHaveLength(1);
    });
  });

  describe('search', () => {
    it('should search tracks by query', async () => {
      const mockTracks = [
        {
          id: '1',
          title: 'Search Result',
          artist: 'Artist',
          duration: 200,
          play_count: 0,
          like_count: 0,
          genre: 'Rock',
          status: 'completed',
          created_at: '2024-01-01T00:00:00Z',
        },
      ];

      vi.mocked(api.get).mockResolvedValue(mockTracks);

      const result = await trackService.search('rock');

      expect(api.get).toHaveBeenCalledWith('/tracks/search', { q: 'rock' });
      expect(result.tracks).toHaveLength(1);
      expect(result.tracks[0].title).toBe('Search Result');
    });
  });

  describe('get', () => {
    it('should get a track by id', async () => {
      const mockTrack = {
        id: '1',
        title: 'Test Track',
        artist: 'Test Artist',
        album: 'Test Album',
        duration: 180,
        play_count: 100,
        like_count: 50,
        genre: 'Electronic',
        status: 'completed',
        created_at: '2024-01-01T00:00:00Z',
      };

      vi.mocked(api.get).mockResolvedValue(mockTrack);

      const result = await trackService.get('1');

      expect(api.get).toHaveBeenCalledWith('/tracks/1');
      expect(result.track).toBeDefined();
      expect(result.track.id).toBe('1');
      expect(result.track.title).toBe('Test Track');
    });
  });

  describe('update', () => {
    it('should update a track', async () => {
      const mockTrack = {
        id: '1',
        title: 'Updated Track',
        artist: 'Test Artist',
        duration: 180,
        play_count: 0,
        like_count: 0,
        genre: 'Electronic',
        status: 'completed',
        created_at: '2024-01-01T00:00:00Z',
      };

      vi.mocked(api.put).mockResolvedValue(mockTrack);

      const result = await trackService.update('1', {
        title: 'Updated Track',
        genre: 'Electronic',
      });

      expect(api.put).toHaveBeenCalledWith('/tracks/1', {
        title: 'Updated Track',
        genre: 'Electronic',
      });
      expect(result.track.title).toBe('Updated Track');
    });
  });

  describe('delete', () => {
    it('should delete a track', async () => {
      vi.mocked(api.delete).mockResolvedValue({});

      await trackService.delete('1');

      expect(api.delete).toHaveBeenCalledWith('/tracks/1');
    });
  });

  describe('like', () => {
    it('should like a track', async () => {
      vi.mocked(api.post).mockResolvedValue({});

      await trackService.like('1');

      expect(api.post).toHaveBeenCalledWith('/tracks/1/like');
    });
  });

  describe('unlike', () => {
    it('should unlike a track', async () => {
      vi.mocked(api.delete).mockResolvedValue({});

      await trackService.unlike('1');

      expect(api.delete).toHaveBeenCalledWith('/tracks/1/like');
    });
  });

  describe('recordPlay', () => {
    it('should record a play', async () => {
      vi.mocked(api.post).mockResolvedValue({});

      await trackService.recordPlay('1');

      expect(api.post).toHaveBeenCalledWith('/tracks/1/play');
    });
  });

  describe('download', () => {
    it('should open download URL in new window', () => {
      const windowOpenSpy = vi
        .spyOn(window, 'open')
        .mockImplementation(() => null);

      trackService.download('1');

      expect(windowOpenSpy).toHaveBeenCalledWith(
        `${API_URL}/tracks/1/download`,
        '_blank',
      );

      windowOpenSpy.mockRestore();
    });
  });

  describe('duration formatting', () => {
    it('should format duration correctly', async () => {
      const mockTrack = {
        id: '1',
        title: 'Test Track',
        artist: 'Test Artist',
        duration: 125, // 2 minutes 5 seconds
        play_count: 0,
        like_count: 0,
        genre: 'Electronic',
        status: 'completed',
        created_at: '2024-01-01T00:00:00Z',
      };

      vi.mocked(api.get).mockResolvedValue(mockTrack);

      const result = await trackService.get('1');

      expect(result.track.duration).toBe('2:05');
      expect(result.track.durationSec).toBe(125);
    });

    it('should handle zero duration', async () => {
      const mockTrack = {
        id: '1',
        title: 'Test Track',
        artist: 'Test Artist',
        duration: 0,
        play_count: 0,
        like_count: 0,
        genre: 'Electronic',
        status: 'completed',
        created_at: '2024-01-01T00:00:00Z',
      };

      vi.mocked(api.get).mockResolvedValue(mockTrack);

      const result = await trackService.get('1');

      expect(result.track.duration).toBe('0:00');
    });
  });
});
