import { describe, it, expect, vi, beforeEach } from 'vitest';
import {
  adaptBitrate,
  AdaptBitrateRequest,
  AdaptBitrateResponse,
} from './bitrateService';
import { apiClient } from '@/services/api/client';

// Mock du client API
vi.mock('@/services/api/client', () => ({
  apiClient: {
    post: vi.fn(),
  },
}));

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

  describe('adaptBitrate', () => {
    it('should successfully adapt bitrate and return recommended bitrate', async () => {
      const trackId = 123;
      const request: AdaptBitrateRequest = {
        current_bitrate: 128,
        bandwidth: 10485760, // 10 Mbps
        buffer_level: 0.5,
      };

      const mockResponse: AdaptBitrateResponse = {
        recommended_bitrate: 320,
      };

      (apiClient.post as any).mockResolvedValue({
        data: mockResponse,
      });

      const result = await adaptBitrate(trackId, request);

      expect(apiClient.post).toHaveBeenCalledWith(
        `/tracks/${trackId}/bitrate/adapt`,
        request,
      );
      expect(result).toEqual(mockResponse);
      expect(result.recommended_bitrate).toBe(320);
    });

    it('should handle bitrate decrease', async () => {
      const trackId = 456;
      const request: AdaptBitrateRequest = {
        current_bitrate: 320,
        bandwidth: 307200, // 300 kbps
        buffer_level: 0.5,
      };

      const mockResponse: AdaptBitrateResponse = {
        recommended_bitrate: 192,
      };

      (apiClient.post as any).mockResolvedValue({
        data: mockResponse,
      });

      const result = await adaptBitrate(trackId, request);

      expect(result.recommended_bitrate).toBe(192);
    });

    it('should handle no bitrate change', async () => {
      const trackId = 789;
      const request: AdaptBitrateRequest = {
        current_bitrate: 128,
        bandwidth: 10485760,
        buffer_level: 0.15, // Low buffer prevents increase
      };

      const mockResponse: AdaptBitrateResponse = {
        recommended_bitrate: 128,
      };

      (apiClient.post as any).mockResolvedValue({
        data: mockResponse,
      });

      const result = await adaptBitrate(trackId, request);

      expect(result.recommended_bitrate).toBe(128);
    });

    it('should throw error on 401 Unauthorized', async () => {
      const trackId = 123;
      const request: AdaptBitrateRequest = {
        current_bitrate: 128,
        bandwidth: 10485760,
        buffer_level: 0.5,
      };

      const error = {
        response: {
          status: 401,
          data: { error: 'unauthorized' },
        },
      };

      (apiClient.post as any).mockRejectedValue(error);

      await expect(adaptBitrate(trackId, request)).rejects.toThrow(
        'Unauthorized: Please log in to adapt bitrate',
      );
    });

    it('should throw error on 400 Bad Request', async () => {
      const trackId = 123;
      const request: AdaptBitrateRequest = {
        current_bitrate: 128,
        bandwidth: 10485760,
        buffer_level: 1.5, // Invalid buffer level
      };

      const error = {
        response: {
          status: 400,
          data: {
            error: 'invalid buffer level: 1.5 (must be between 0.0 and 1.0)',
          },
        },
      };

      (apiClient.post as any).mockRejectedValue(error);

      await expect(adaptBitrate(trackId, request)).rejects.toThrow(
        'Invalid request: invalid buffer level: 1.5 (must be between 0.0 and 1.0)',
      );
    });

    it('should throw error on 404 Not Found', async () => {
      const trackId = 999;
      const request: AdaptBitrateRequest = {
        current_bitrate: 128,
        bandwidth: 10485760,
        buffer_level: 0.5,
      };

      const error = {
        response: {
          status: 404,
          data: { error: 'track not found' },
        },
      };

      (apiClient.post as any).mockRejectedValue(error);

      await expect(adaptBitrate(trackId, request)).rejects.toThrow(
        'Track not found: 999',
      );
    });

    it('should throw error on 500 Server Error', async () => {
      const trackId = 123;
      const request: AdaptBitrateRequest = {
        current_bitrate: 128,
        bandwidth: 10485760,
        buffer_level: 0.5,
      };

      const error = {
        response: {
          status: 500,
          data: { error: 'internal server error' },
        },
      };

      (apiClient.post as any).mockRejectedValue(error);

      await expect(adaptBitrate(trackId, request)).rejects.toThrow(
        'Server error: internal server error',
      );
    });

    it('should throw error on network error', async () => {
      const trackId = 123;
      const request: AdaptBitrateRequest = {
        current_bitrate: 128,
        bandwidth: 10485760,
        buffer_level: 0.5,
      };

      const error = {
        request: {},
        message: 'Network Error',
      };

      (apiClient.post as any).mockRejectedValue(error);

      await expect(adaptBitrate(trackId, request)).rejects.toThrow(
        'Network error: Unable to reach the server',
      );
    });

    it('should throw error on unknown error', async () => {
      const trackId = 123;
      const request: AdaptBitrateRequest = {
        current_bitrate: 128,
        bandwidth: 10485760,
        buffer_level: 0.5,
      };

      const error = {
        message: 'Unknown error occurred',
      };

      (apiClient.post as any).mockRejectedValue(error);

      await expect(adaptBitrate(trackId, request)).rejects.toThrow(
        'Error: Unknown error occurred',
      );
    });

    it('should handle error without response data', async () => {
      const trackId = 123;
      const request: AdaptBitrateRequest = {
        current_bitrate: 128,
        bandwidth: 10485760,
        buffer_level: 0.5,
      };

      const error = {
        response: {
          status: 400,
          data: {},
        },
        message: 'Bad Request',
      };

      (apiClient.post as any).mockRejectedValue(error);

      await expect(adaptBitrate(trackId, request)).rejects.toThrow(
        'Invalid request: Bad Request',
      );
    });

    it('should handle different bitrate values', async () => {
      const testCases = [
        { current: 128, recommended: 192 },
        { current: 192, recommended: 320 },
        { current: 320, recommended: 192 },
        { current: 128, recommended: 128 },
      ];

      for (const testCase of testCases) {
        const request: AdaptBitrateRequest = {
          current_bitrate: testCase.current,
          bandwidth: 10485760,
          buffer_level: 0.5,
        };

        const mockResponse: AdaptBitrateResponse = {
          recommended_bitrate: testCase.recommended,
        };

        (apiClient.post as any).mockResolvedValue({
          data: mockResponse,
        });

        const result = await adaptBitrate(123, request);
        expect(result.recommended_bitrate).toBe(testCase.recommended);
      }
    });
  });
});
