import { NextRequest, NextResponse } from 'next/server';
import { assertCronAuthorized } from '@/lib/cron/auth';
import { withJobRun } from '@/lib/cron/jobRun';
import { prisma } from '@/lib/db/client';
import { discoverGames } from '@/lib/igdb/client';
import { mapIgdbToFacts, computeSourceDataHash, slugify } from '@/lib/content/mapper';
import { isExcluded } from '@/lib/config/overrides';

export const runtime = 'nodejs';
export const maxDuration = 60;

const PAGE_SIZE = 50;

/**
 * "Continuously discover and expand to new games over time" — this is the
 * whole implementation of that sentence. One page of IGDB's catalog per
 * run, ordered by popularity, cursor persisted in SyncCursor so repeated
 * runs make forward progress instead of re-scanning from zero. Wire this
 * to run every 15-30 min via vercel.json or an external scheduler.
 */
export async function POST(req: NextRequest) {
  const authError = assertCronAuthorized(req);
  if (authError) return authError;

  const outcome = await withJobRun('discover-games', async () => {
    const cursor = await prisma.syncCursor.upsert({
      where: { source: 'igdb' },
      create: { source: 'igdb', offset: 0 },
      update: {},
    });

    const games = await discoverGames(cursor.offset, PAGE_SIZE);

    let itemsOk = 0;
    let itemsFailed = 0;
    let created = 0;
    let skippedExcluded = 0;

    for (const igdbGame of games) {
      try {
        const facts = mapIgdbToFacts(igdbGame);
        const slug = facts.slug || slugify(facts.name);

        if (await isExcluded(slug)) {
          skippedExcluded++;
          continue;
        }

        const existing = await prisma.game.findUnique({ where: { igdbId: igdbGame.id } });
        if (existing) {
          // Already known — don't touch its content status here, that's
          // refresh-stale's job. Just note we've seen it.
          await prisma.game.update({ where: { id: existing.id }, data: { lastCheckedAt: new Date() } });
          itemsOk++;
          continue;
        }

        await prisma.game.create({
          data: {
            igdbId: igdbGame.id,
            slug,
            name: facts.name,
            summary: facts.summary,
            storyline: facts.storyline,
            releaseDate: facts.releaseDate ? new Date(facts.releaseDate) : null,
            genres: facts.genres,
            platforms: facts.platforms,
            developers: facts.developers,
            publishers: facts.publishers,
            gameModes: facts.gameModes,
            ageRating: facts.ageRating,
            officialUrl: igdbGame.url,
            coverUrl: facts.coverUrl,
            screenshots: facts.screenshots,
            videoIds: facts.videoIds,
            igdbRating: facts.rating,
            igdbRatingCount: facts.ratingCount,
            status: 'DISCOVERED',
            sourceDataHash: computeSourceDataHash(facts),
            lastCheckedAt: new Date(),
          },
        });
        created++;
        itemsOk++;
      } catch (err) {
        itemsFailed++;
        console.error(`[discover-games] Failed on IGDB id ${igdbGame.id}:`, err);
      }
    }

    // Wrap around once we run past the end of the catalog rather than
    // erroring — discovery is meant to run forever.
    const nextOffset = games.length < PAGE_SIZE ? 0 : cursor.offset + PAGE_SIZE;
    await prisma.syncCursor.update({
      where: { source: 'igdb' },
      data: {
        offset: nextOffset,
        lastRunAt: new Date(),
        totalDiscovered: { increment: created },
      },
    });

    return {
      itemsSeen: games.length,
      itemsOk,
      itemsFailed,
      detail: { created, skippedExcluded, nextOffset, wrapped: games.length < PAGE_SIZE },
    };
  });

  return NextResponse.json(outcome);
}

// Vercel Cron invokes scheduled routes with GET; scripts/run-cron.ts (for
// VPS/manual use) uses POST. Both are accepted and do the same thing.
export const GET = POST;
