← back to Wine Finder Next

src/api/wineProviders.ts

133 lines

/**
 * Wine Providers API - Aggregates auction and retail wine data
 */

import { apiClient } from './httpClient';
import { WineListing, PriceHistoryPoint } from '../types/wine';

interface SearchResponse {
  wines: WineListing[];
}

interface PriceHistoryResponse {
  history: PriceHistoryPoint[];
}

/**
 * Search WineBid auctions
 */
export async function fetchFromWineBid(query: string): Promise<WineListing[]> {
  try {
    const response = await apiClient.get<SearchResponse>('/winebid/search', { q: query });
    return response.wines || [];
  } catch (error) {
    console.error('WineBid fetch failed:', error);
    return [];
  }
}

/**
 * Search Sotheby's wine auctions
 */
export async function fetchFromSothebys(query: string): Promise<WineListing[]> {
  try {
    const response = await apiClient.get<SearchResponse>('/sothebys/search', { q: query });
    return response.wines || [];
  } catch (error) {
    console.error('Sothebys fetch failed:', error);
    return [];
  }
}

/**
 * Search Zachys wine auctions
 */
export async function fetchFromZachys(query: string): Promise<WineListing[]> {
  try {
    const response = await apiClient.get<SearchResponse>('/zachys/search', { q: query });
    return response.wines || [];
  } catch (error) {
    console.error('Zachys fetch failed:', error);
    return [];
  }
}

/**
 * Search Wine.com retail
 */
export async function fetchFromWineCom(query: string): Promise<WineListing[]> {
  try {
    const response = await apiClient.get<SearchResponse>('/winecom/search', { q: query });
    return response.wines || [];
  } catch (error) {
    console.error('Wine.com fetch failed:', error);
    return [];
  }
}

/**
 * Search Vivino retail
 */
export async function fetchFromVivino(query: string): Promise<WineListing[]> {
  try {
    const response = await apiClient.get<SearchResponse>('/vivino/search', { q: query });
    return response.wines || [];
  } catch (error) {
    console.error('Vivino fetch failed:', error);
    return [];
  }
}

/**
 * Search Wine-Searcher (aggregates retail + auction)
 */
export async function fetchFromWineSearcher(query: string): Promise<WineListing[]> {
  try {
    const response = await apiClient.get<SearchResponse>('/wine-searcher/search', { q: query });
    return response.wines || [];
  } catch (error) {
    console.error('Wine-Searcher fetch failed:', error);
    return [];
  }
}

/**
 * Search ALL providers in parallel and aggregate results
 */
export async function searchWineEverywhere(query: string): Promise<WineListing[]> {
  const results = await Promise.allSettled([
    fetchFromWineBid(query),
    fetchFromSothebys(query),
    fetchFromZachys(query),
    fetchFromWineCom(query),
    fetchFromVivino(query),
    fetchFromWineSearcher(query),
  ]);

  const allWines: WineListing[] = [];

  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      allWines.push(...result.value);
    } else {
      const providers = ['WineBid', 'Sothebys', 'Zachys', 'Wine.com', 'Vivino', 'Wine-Searcher'];
      console.warn(`${providers[index]} search failed:`, result.reason);
    }
  });

  return allWines;
}

/**
 * Get price history for a specific wine
 */
export async function fetchPriceHistory(wineId: string): Promise<PriceHistoryPoint[]> {
  try {
    const response = await apiClient.get<PriceHistoryResponse>('/price-history', { wineId });
    return response.history || [];
  } catch (error) {
    console.error('Price history fetch failed:', error);
    return [];
  }
}