/**
 * ===================================================
 * BATCH PREDICTION PIPELINE — V30
 * ===================================================
 * Processes all upcoming matches (NS) and generates
 * predictions by calling the AI Engine.
 * Saves results to the predictions table.
 *
 * Usage: npx ts-node --transpile-only -r tsconfig-paths/register src/scripts/batch-predict.ts
 */

import { PrismaClient } from "@prisma/client";
import axios from "axios";

const prisma = new PrismaClient();

const AI_ENGINE_URL = process.env.AI_ENGINE_URL || "http://127.0.0.1:3005";
const BATCH_SIZE = 5;
const MAX_MATCHES_TO_PROCESS = 1000; // Limit for local testing/batch capacity

async function runBatchPrediction() {
  console.log("🗓 BATCH PREDICTION PIPELINE STARTING");
  console.log("════════════════════════════════════════════════════════");

  // 1. Health check
  try {
    const health = await axios.get(`${AI_ENGINE_URL}/health`, {
      timeout: 5000,
    });
    console.log(`✅ AI Engine Health: ${JSON.stringify(health.data)}`);
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
  } catch (e) {
    console.error("❌ AI Engine not reachable at", AI_ENGINE_URL);
    process.exit(1);
  }

  // 2. Load upcoming matches (Not Started)
  const upcomingMatches = await prisma.match.findMany({
    where: {
      status: "NS",
      mstUtc: {
        gte: Math.floor(Date.now() / 1000), // Future matches
      },
      sport: "football",
    },
    orderBy: { mstUtc: "asc" },
    take: MAX_MATCHES_TO_PROCESS,
    select: {
      id: true,
      homeTeam: { select: { name: true } },
      awayTeam: { select: { name: true } },
      mstUtc: true,
    },
  });

  console.log(
    `\n📥 Found ${upcomingMatches.length} upcoming matches to process.`,
  );

  // 3. Process matches in batches
  let processedCount = 0;
  let successCount = 0;

  for (let i = 0; i < upcomingMatches.length; i += BATCH_SIZE) {
    const batch = upcomingMatches.slice(i, i + BATCH_SIZE);

    console.log(
      `\n⏳ Processing batch ${Math.floor(i / BATCH_SIZE) + 1} (${batch.length} matches)...`,
    );

    const promises = batch.map(async (match) => {
      try {
        const response = await axios.post(
          `${AI_ENGINE_URL}/v20plus/analyze/${match.id}`,
          {},
          { timeout: 20000 },
        );

        const data = response.data;
        if (!data || !data.predictions) {
          return false;
        }

        // Use the entire response payload so frontend gets the expected MatchPredictionDto schema
        const modelOutput = data;

        // Cache result in predictions table
        await prisma.prediction.upsert({
          where: { matchId: match.id },
          create: {
            matchId: match.id,
            predictionJson: modelOutput,
          },
          update: {
            predictionJson: modelOutput,
            updatedAt: new Date(),
          },
        });

        console.log(
          `  ✅ Cached prediction for: ${match.homeTeam?.name} vs ${match.awayTeam?.name} (${match.mstUtc})`,
        );
        return true;
      } catch (e: unknown) {
        const err = e as Error;
        console.error(
          `  ❌ Failed for match ${match.id}:`,
          err?.message || "Unknown error",
        );
        return false;
      }
    });

    const results = await Promise.all(promises);
    successCount += results.filter(Boolean).length;
    processedCount += batch.length;
  }

  console.log("\n════════════════════════════════════════════════════════");
  console.log(`🎉 BATCH PROCESS COMPLETE`);
  console.log(`  Total Processed: ${processedCount}`);
  console.log(`  Successfully Updated/Created: ${successCount}`);
  console.log(`  Failed: ${processedCount - successCount}`);
  console.log("════════════════════════════════════════════════════════");

  await prisma.$disconnect();
}

runBatchPrediction().catch((e: unknown) => {
  const err = e as Error;
  console.error(err);
  void prisma.$disconnect();
  process.exit(1);
});
