import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AxiosError } from 'axios';
import { marketplaceService } from './marketplaceService';
import { apiClient } from './api/client';
import type { Product, Order, ProductStatus } from '../types/marketplace';

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

const mockedApiClient = apiClient as {
  get: ReturnType<typeof vi.fn>;
  post: ReturnType<typeof vi.fn>;
};

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

  describe('fetchProducts', () => {
    it('should fetch products without filters', async () => {
      const mockProducts: Product[] = [
        {
          id: '1',
          name: 'Test Product',
          description: 'Test Description',
          price: 10.99,
          status: 'active' as ProductStatus,
          seller_id: 'seller-1',
          created_at: '2024-01-01T00:00:00Z',
        },
      ];

      mockedApiClient.get.mockResolvedValue({
        data: {
          products: mockProducts,
          total: 1,
          page: 1,
          limit: 20,
          total_pages: 1,
        },
      });

      const result = await marketplaceService.fetchProducts();

      expect(result.products).toEqual(mockProducts);
      expect(result.total).toBe(1);
      expect(mockedApiClient.get).toHaveBeenCalledWith('/marketplace/products');
    });

    it('should fetch products with filters', async () => {
      const mockProducts: Product[] = [];

      mockedApiClient.get.mockResolvedValue({
        data: {
          products: mockProducts,
          total: 0,
          page: 1,
          limit: 20,
          total_pages: 0,
        },
      });

      await marketplaceService.fetchProducts(
        {
          status: 'active' as ProductStatus,
          seller_id: 'seller-1',
          min_price: 10,
          max_price: 100,
          search: 'test',
        },
        { page: 1, limit: 20 },
      );

      expect(mockedApiClient.get).toHaveBeenCalledWith(
        '/marketplace/products?status=active&seller_id=seller-1&min_price=10&max_price=100&search=test&page=1&limit=20',
      );
    });

    it('should handle array response format (backward compatibility)', async () => {
      const mockProducts: Product[] = [
        {
          id: '1',
          name: 'Test Product',
          description: 'Test Description',
          price: 10.99,
          status: 'active' as ProductStatus,
          seller_id: 'seller-1',
          created_at: '2024-01-01T00:00:00Z',
        },
      ];

      mockedApiClient.get.mockResolvedValue({
        data: mockProducts,
      });

      const result = await marketplaceService.fetchProducts();

      expect(result.products).toEqual(mockProducts);
      expect(result.total).toBe(1);
      expect(result.page).toBe(1);
    });

    it('should throw error on fetch failure', async () => {
      const mockError = new AxiosError('Fetch failed');
      mockError.response = {
        status: 500,
        data: { error: 'Internal server error' },
      } as any;

      mockedApiClient.get.mockRejectedValue(mockError);

      await expect(marketplaceService.fetchProducts()).rejects.toThrow();
    });
  });

  describe('createProduct', () => {
    it('should create a product successfully', async () => {
      const mockProduct: Product = {
        id: '1',
        name: 'New Product',
        description: 'New Description',
        price: 19.99,
        status: 'active' as ProductStatus,
        seller_id: 'seller-1',
        created_at: '2024-01-01T00:00:00Z',
      };

      mockedApiClient.post.mockResolvedValue({
        data: mockProduct,
      });

      const result = await marketplaceService.createProduct({
        name: 'New Product',
        description: 'New Description',
        price: 19.99,
        product_type: 'track',
      });

      expect(result).toEqual(mockProduct);
      expect(mockedApiClient.post).toHaveBeenCalledWith(
        '/marketplace/products',
        {
          name: 'New Product',
          description: 'New Description',
          price: 19.99,
          product_type: 'track',
        },
      );
    });

    it('should throw error on creation failure', async () => {
      const mockError = new AxiosError('Creation failed');
      mockError.response = {
        status: 403,
        data: { error: 'Permission denied' },
      } as any;

      mockedApiClient.post.mockRejectedValue(mockError);

      await expect(
        marketplaceService.createProduct({
          name: 'New Product',
          description: 'New Description',
          price: 19.99,
          product_type: 'track',
        }),
      ).rejects.toThrow();
    });
  });

  describe('createOrder', () => {
    it('should create an order successfully', async () => {
      const mockOrder: Order = {
        id: 'order-1',
        user_id: 'user-1',
        items: [{ product_id: 'product-1', quantity: 1 }],
        total: 19.99,
        status: 'pending',
        created_at: '2024-01-01T00:00:00Z',
      };

      mockedApiClient.post.mockResolvedValue({
        data: mockOrder,
      });

      const result = await marketplaceService.createOrder([
        { product_id: 'product-1' },
      ]);

      expect(result).toEqual(mockOrder);
      expect(mockedApiClient.post).toHaveBeenCalledWith('/marketplace/orders', {
        items: [{ product_id: 'product-1' }],
      });
    });

    it('should throw error on order creation failure', async () => {
      const mockError = new AxiosError('Order creation failed');
      mockError.response = {
        status: 400,
        data: { error: 'Invalid product' },
      } as any;

      mockedApiClient.post.mockRejectedValue(mockError);

      await expect(
        marketplaceService.createOrder([{ product_id: 'invalid-product' }]),
      ).rejects.toThrow();
    });
  });

  describe('purchaseProduct', () => {
    it('should purchase a single product successfully', async () => {
      const mockOrder: Order = {
        id: 'order-1',
        user_id: 'user-1',
        items: [{ product_id: 'product-1', quantity: 1 }],
        total: 19.99,
        status: 'pending',
        created_at: '2024-01-01T00:00:00Z',
      };

      mockedApiClient.post.mockResolvedValue({
        data: mockOrder,
      });

      const result = await marketplaceService.purchaseProduct('product-1');

      expect(result).toEqual(mockOrder);
      expect(mockedApiClient.post).toHaveBeenCalledWith('/marketplace/orders', {
        items: [{ product_id: 'product-1' }],
      });
    });
  });

  describe('getDownloadLink', () => {
    it('should get download link successfully', async () => {
      const mockResponse = { url: 'https://example.com/download/product-1' };

      mockedApiClient.get.mockResolvedValue({
        data: mockResponse,
      });

      const result = await marketplaceService.getDownloadLink('product-1');

      expect(result).toBe('https://example.com/download/product-1');
      expect(mockedApiClient.get).toHaveBeenCalledWith(
        '/marketplace/download/product-1',
      );
    });

    it('should throw error on download link failure', async () => {
      const mockError = new AxiosError('Download link failed');
      mockError.response = {
        status: 403,
        data: { error: 'No license found' },
      } as any;

      mockedApiClient.get.mockRejectedValue(mockError);

      await expect(
        marketplaceService.getDownloadLink('product-1'),
      ).rejects.toThrow();
    });
  });
});
