← back to Wine Finder Next

app/api/ingest/vivino/route.ts

103 lines

// app/api/ingest/vivino/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getDb } from '@/lib/db';

export async function POST(req: NextRequest) {
  try {
    const body = await req.json();
    const { wines } = body;

    if (!Array.isArray(wines)) {
      return NextResponse.json({ error: 'wines array required' }, { status: 400 });
    }

    const db = getDb();
    const insertWine = db.prepare(`
      INSERT OR REPLACE INTO wines (
        name, varietal, vintage, region, country, 
        alc_percent, tasting_notes, vivino_id, 
        image_url, critic_scores
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `);

    const insertPrice = db.prepare(`
      INSERT INTO wine_prices (wine_id, vendor, price, collected_at, product_id, metadata)
      VALUES (?, 'vivino', ?, datetime('now'), ?, ?)
    `);

    const insertRating = db.prepare(`
      INSERT OR REPLACE INTO wine_ratings (wine_id, vendor, rating, review_count, collected_at)
      VALUES (?, 'vivino', ?, ?, datetime('now'))
    `);

    let processed = 0;
    let errors = 0;

    for (const wine of wines) {
      try {
        // Insert or update wine
        const wineResult = insertWine.run(
          wine.name || '',
          wine.grape || wine.varietal || null,
          wine.vintage || null,
          wine.region?.name || wine.region || null,
          wine.region?.country?.name || wine.country || null,
          wine.alcohol || null,
          wine.taste?.description || wine.description || null,
          wine.vivino_id || wine.id || null,
          wine.image?.location || wine.image_url || null,
          wine.style ? JSON.stringify(wine.style) : null
        );

        // Insert price if provided
        if (wine.price?.amount) {
          const metadata = {
            currency: wine.price.currency,
            discounted_from: wine.price.discounted_from,
            bottle_size: wine.bottle_size
          };

          insertPrice.run(
            wineResult.lastInsertRowid,
            wine.price.amount,
            wine.vivino_id || wine.id,
            JSON.stringify(metadata)
          );
        }

        // Insert rating if provided
        if (wine.rating?.average) {
          insertRating.run(
            wineResult.lastInsertRowid,
            wine.rating.average,
            wine.rating.count || 0
          );
        }

        processed++;
      } catch (error) {
        console.error('Error processing wine:', error);
        errors++;
      }
    }

    return NextResponse.json({
      success: true,
      processed,
      errors,
      message: `Processed ${processed} wines from Vivino`
    });

  } catch (error) {
    console.error('Vivino ingest error:', error);
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
  }
}

export async function GET() {
  // Health check endpoint
  return NextResponse.json({ 
    status: 'Vivino ingest endpoint ready',
    timestamp: new Date().toISOString()
  });
}