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

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

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

  describe('list', () => {
    it('should return list of playlists', async () => {
      const result = await playlistService.list();

      expect(result.playlists).toBeDefined();
      expect(Array.isArray(result.playlists)).toBe(true);
      expect(result.playlists.length).toBeGreaterThan(0);
    });

    it('should return playlists with correct structure', async () => {
      const result = await playlistService.list();

      result.playlists.forEach((playlist) => {
        expect(playlist).toHaveProperty('id');
        expect(playlist).toHaveProperty('title');
        expect(playlist).toHaveProperty('creator');
        expect(playlist).toHaveProperty('trackCount');
        expect(playlist).toHaveProperty('likes');
      });
    });
  });

  describe('search', () => {
    it('should search playlists by query', async () => {
      const result = await playlistService.search('Cyberpunk');

      expect(result.playlists).toBeDefined();
      expect(Array.isArray(result.playlists)).toBe(true);
      // Should find playlists matching the query
      result.playlists.forEach((playlist) => {
        expect(playlist.title.toLowerCase()).toContain('cyberpunk');
      });
    });

    it('should return empty array for no matches', async () => {
      const result = await playlistService.search('nonexistentquery12345');

      expect(result.playlists).toBeDefined();
      expect(result.playlists.length).toBe(0);
    });

    it('should be case insensitive', async () => {
      const result1 = await playlistService.search('cyberpunk');
      const result2 = await playlistService.search('CYBERPUNK');

      expect(result1.playlists.length).toBe(result2.playlists.length);
    });
  });

  describe('get', () => {
    it('should get a playlist by id', async () => {
      const result = await playlistService.get('1');

      expect(result.playlist).toBeDefined();
      expect(result.playlist?.id).toBe('1');
    });

    it('should return first playlist if id not found', async () => {
      const result = await playlistService.get('nonexistent-id');

      expect(result.playlist).toBeDefined();
      // Should return first playlist as fallback
      expect(result.playlist?.id).toBeDefined();
    });
  });

  describe('create', () => {
    it('should create a new playlist', async () => {
      const newPlaylistData = {
        title: 'New Playlist',
        description: 'Test description',
        isPublic: true,
      };

      const result = await playlistService.create(newPlaylistData);

      expect(result).toBeDefined();
      expect(result.id).toBeDefined();
      expect(result.title).toBe('New Playlist');
      expect(result.trackCount).toBe(0);
      expect(result.likes).toBe(0);
      expect(result.creator).toBe('You');
    });

    it('should generate unique id for new playlist', async () => {
      const data1 = { title: 'Playlist 1' };
      const data2 = { title: 'Playlist 2' };

      const result1 = await playlistService.create(data1);
      // Advance time to ensure different timestamp
      vi.advanceTimersByTime(1000);
      const result2 = await playlistService.create(data2);

      expect(result1.id).not.toBe(result2.id);
    });
  });

  describe('update', () => {
    it('should update a playlist', async () => {
      await expect(
        playlistService.update('1', { title: 'Updated' }),
      ).resolves.not.toThrow();
    });
  });

  describe('delete', () => {
    it('should delete a playlist', async () => {
      await expect(playlistService.delete('1')).resolves.not.toThrow();
    });
  });

  describe('addTrack', () => {
    it('should add a track to playlist', async () => {
      await expect(playlistService.addTrack()).resolves.not.toThrow();
    });
  });

  describe('removeTrack', () => {
    it('should remove a track from playlist', async () => {
      await expect(playlistService.removeTrack()).resolves.not.toThrow();
    });
  });

  describe('reorderTracks', () => {
    it('should reorder tracks in playlist', async () => {
      await expect(playlistService.reorderTracks()).resolves.not.toThrow();
    });
  });

  describe('getRecommendations', () => {
    it('should get playlist recommendations', async () => {
      const result = await playlistService.getRecommendations();

      expect(result).toBeDefined();
      expect(result.tracks).toBeDefined();
      expect(Array.isArray(result.tracks)).toBe(true);
    });
  });

  describe('addCollaborator', () => {
    it('should add a collaborator', async () => {
      await expect(playlistService.addCollaborator()).resolves.not.toThrow();
    });
  });

  describe('getCollaborators', () => {
    it('should get playlist collaborators', async () => {
      const result = await playlistService.getCollaborators();

      expect(result).toBeDefined();
      expect(result.collaborators).toBeDefined();
      expect(Array.isArray(result.collaborators)).toBe(true);
    });
  });

  describe('updateCollaborator', () => {
    it('should update collaborator permissions', async () => {
      await expect(playlistService.updateCollaborator()).resolves.not.toThrow();
    });
  });

  describe('removeCollaborator', () => {
    it('should remove a collaborator', async () => {
      await expect(playlistService.removeCollaborator()).resolves.not.toThrow();
    });
  });

  describe('createShareLink', () => {
    it('should create a share link', async () => {
      const result = await playlistService.createShareLink();

      expect(result).toBeDefined();
      expect(result.share_url).toBeDefined();
      expect(typeof result.share_url).toBe('string');
      expect(result.share_url).toContain('veza.io');
    });
  });
});
