← back to Wine Finder Next

app/arbitrage/page.tsx

181 lines

'use client';

import { useState } from 'react';
import SearchBar from '@/src/components/SearchBar';
import ListingsTable from '@/src/components/ListingsTable';
import PriceHistoryChart from '@/src/components/PriceHistoryChart';
import { searchWineEverywhere, fetchPriceHistory } from '@/src/api/wineProviders';
import { WineListing, PriceHistoryPoint } from '@/src/types/wine';
import { TOP_10_AUCTION_WINES } from '@/src/data/topAuctionWines';

export default function ArbitrageFinder() {
  const [listings, setListings] = useState<WineListing[]>([]);
  const [priceHistory, setPriceHistory] = useState<PriceHistoryPoint[]>([]);
  const [selectedWine, setSelectedWine] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [lastQuery, setLastQuery] = useState('');

  const handleSearch = async (query: string) => {
    setIsLoading(true);
    setLastQuery(query);

    try {
      const wines = await searchWineEverywhere(query);
      setListings(wines);

      // Load price history for first wine (if any)
      if (wines.length > 0) {
        const firstWine = wines[0];
        setSelectedWine(firstWine.name);
        const history = await fetchPriceHistory(firstWine.id);
        setPriceHistory(history);
      }
    } catch (error) {
      console.error('Search failed:', error);
      setListings([]);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <main className="min-h-screen bg-gradient-to-br from-purple-50 via-pink-50 to-red-50">
      {/* Header */}
      <div className="bg-gradient-to-r from-purple-900 via-pink-900 to-red-900 text-white py-12 shadow-2xl">
        <div className="container mx-auto px-4">
          <div className="text-center mb-8">
            <div className="text-6xl mb-4">💎</div>
            <h1 className="text-5xl font-black mb-4 bg-clip-text text-transparent bg-gradient-to-r from-yellow-200 via-pink-200 to-purple-200">
              Wine Arbitrage Finder
            </h1>
            <p className="text-xl text-purple-200 max-w-3xl mx-auto">
              Find profitable opportunities by comparing auction prices vs retail prices across all major wine sources
            </p>
          </div>

          <SearchBar onSearch={handleSearch} isLoading={isLoading} />

          {/* Stats Bar */}
          {listings.length > 0 && (
            <div className="mt-8 grid grid-cols-3 gap-4 max-w-3xl mx-auto">
              <div className="bg-white/10 backdrop-blur rounded-lg p-4 text-center border border-white/20">
                <div className="text-3xl font-black text-yellow-300">{listings.length}</div>
                <div className="text-sm text-purple-200">Total Listings</div>
              </div>
              <div className="bg-white/10 backdrop-blur rounded-lg p-4 text-center border border-white/20">
                <div className="text-3xl font-black text-green-300">
                  {listings.filter(l => l.provider === 'retail').length}
                </div>
                <div className="text-sm text-purple-200">Retail</div>
              </div>
              <div className="bg-white/10 backdrop-blur rounded-lg p-4 text-center border border-white/20">
                <div className="text-3xl font-black text-blue-300">
                  {listings.filter(l => l.provider === 'auction').length}
                </div>
                <div className="text-sm text-purple-200">Auctions</div>
              </div>
            </div>
          )}
        </div>
      </div>

      {/* Main Content */}
      <div className="container mx-auto px-4 py-12">
        {/* Empty State */}
        {!isLoading && listings.length === 0 && !lastQuery && (
          <div className="text-center py-20">
            <div className="text-8xl mb-6">🔍</div>
            <h2 className="text-3xl font-bold text-gray-800 mb-4">Start Finding Arbitrage Opportunities</h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto mb-8">
              Search for premium wines to compare auction vs retail prices. We search across:
            </p>
            <div className="flex flex-wrap justify-center gap-3 max-w-3xl mx-auto mb-8">
              {['WineBid', 'Sotheby\'s', 'Zachys', 'Wine.com', 'Vivino', 'Wine-Searcher'].map(source => (
                <span key={source} className="px-4 py-2 bg-purple-100 text-purple-700 rounded-full font-semibold text-sm">
                  {source}
                </span>
              ))}
            </div>
            <div className="bg-gradient-to-r from-purple-100 via-pink-100 to-red-100 rounded-2xl p-8 mt-8 border-2 border-purple-300">
              <h3 className="text-2xl font-bold text-center text-gray-800 mb-2">🔥 Top 10 Wines at Auction</h3>
              <p className="text-center text-gray-600 mb-6">Most profitable arbitrage opportunities by brand</p>
              <div className="grid grid-cols-2 md:grid-cols-5 gap-3">
                {TOP_10_AUCTION_WINES.map((wine, idx) => (
                  <button
                    key={wine}
                    onClick={() => handleSearch(wine)}
                    className="group relative px-4 py-3 bg-white hover:bg-gradient-to-r hover:from-purple-600 hover:to-pink-600 text-gray-800 hover:text-white rounded-xl transition-all font-semibold text-sm shadow-md hover:shadow-xl border-2 border-purple-200 hover:border-purple-400 transform hover:scale-105"
                  >
                    <div className="text-xs text-purple-600 group-hover:text-yellow-200 mb-1">#{idx + 1}</div>
                    <div className="font-bold">{wine}</div>
                  </button>
                ))}
              </div>
              <div className="mt-6 text-center text-sm text-gray-500">
                Click any wine to find arbitrage opportunities instantly
              </div>
            </div>
          </div>
        )}

        {/* Loading State */}
        {isLoading && (
          <div className="text-center py-20">
            <div className="inline-block animate-spin rounded-full h-20 w-20 border-t-4 border-b-4 border-purple-600 mb-6"></div>
            <p className="text-xl text-gray-700 font-semibold">Searching all sources...</p>
            <p className="text-sm text-gray-500 mt-2">This may take a moment as we check multiple providers</p>
          </div>
        )}

        {/* No Results */}
        {!isLoading && listings.length === 0 && lastQuery && (
          <div className="text-center py-20">
            <div className="text-8xl mb-6">😕</div>
            <h2 className="text-3xl font-bold text-gray-800 mb-4">No wines found for "{lastQuery}"</h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              Try searching for:
            </p>
            <div className="flex flex-wrap justify-center gap-2 mt-4">
              {['Caymus Cabernet', 'Opus One', 'Silver Oak', 'Screaming Eagle', 'Dom Perignon'].map(suggestion => (
                <button
                  key={suggestion}
                  onClick={() => handleSearch(suggestion)}
                  className="px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-all font-semibold"
                >
                  {suggestion}
                </button>
              ))}
            </div>
          </div>
        )}

        {/* Results */}
        {!isLoading && listings.length > 0 && (
          <>
            <ListingsTable listings={listings} />

            {/* Price History Chart */}
            {priceHistory.length > 0 && (
              <div className="mt-12">
                <PriceHistoryChart history={priceHistory} wineName={selectedWine || undefined} />
              </div>
            )}
          </>
        )}
      </div>

      {/* Footer */}
      <footer className="bg-gradient-to-r from-purple-900 to-pink-900 text-white py-8 mt-20">
        <div className="container mx-auto px-4 text-center">
          <p className="text-purple-200 mb-2">
            Wine Arbitrage Finder - Compare auction vs retail prices
          </p>
          <p className="text-sm text-purple-300">
            Part of Red Thunder Wine Tracker © 2025
          </p>
        </div>
      </footer>
    </main>
  );
}