Implement results sync from football-data.org
This commit is contained in:
@@ -1,4 +1,29 @@
|
|||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from 'next/server'
|
||||||
|
import { prisma } from '@/lib/prisma'
|
||||||
|
import { calculatePoints } from '@/lib/scoring'
|
||||||
|
|
||||||
|
interface FDTeam {
|
||||||
|
tla: string
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FDScore {
|
||||||
|
fullTime: { home: number | null; away: number | null }
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FDMatch {
|
||||||
|
id: number
|
||||||
|
status: 'TIMED' | 'SCHEDULED' | 'IN_PLAY' | 'PAUSED' | 'FINISHED' | 'POSTPONED' | 'SUSPENDED' | 'CANCELLED'
|
||||||
|
homeTeam: FDTeam
|
||||||
|
awayTeam: FDTeam
|
||||||
|
score: FDScore
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStatus(s: FDMatch['status']): 'SCHEDULED' | 'LIVE' | 'FINISHED' {
|
||||||
|
if (s === 'FINISHED') return 'FINISHED'
|
||||||
|
if (s === 'IN_PLAY' || s === 'PAUSED') return 'LIVE'
|
||||||
|
return 'SCHEDULED'
|
||||||
|
}
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
const { searchParams } = new URL(req.url)
|
const { searchParams } = new URL(req.url)
|
||||||
@@ -8,15 +33,80 @@ export async function POST(req: Request) {
|
|||||||
return NextResponse.json({ error: 'No autorizado' }, { status: 401 })
|
return NextResponse.json({ error: 'No autorizado' }, { status: 401 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = process.env.RESULTS_API_URL
|
const apiUrl = process.env.RESULTS_API_URL
|
||||||
if (!url) {
|
const apiKey = process.env.RESULTS_API_KEY
|
||||||
return NextResponse.json({ error: 'RESULTS_API_URL no configurada' }, { status: 400 })
|
if (!apiUrl || !apiKey) {
|
||||||
|
return NextResponse.json({ error: 'RESULTS_API_URL o RESULTS_API_KEY no configuradas' }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implementar cuando se provea la URL del sitio externo
|
let fdMatches: FDMatch[]
|
||||||
// const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.RESULTS_API_KEY}` } })
|
try {
|
||||||
// const data = await res.json()
|
const res = await fetch(apiUrl, {
|
||||||
// ... procesar y actualizar partidos
|
headers: { 'X-Auth-Token': apiKey },
|
||||||
|
cache: 'no-store',
|
||||||
|
})
|
||||||
|
if (!res.ok) {
|
||||||
|
return NextResponse.json({ error: `Error de API externa: ${res.status}` }, { status: 502 })
|
||||||
|
}
|
||||||
|
const data = await res.json()
|
||||||
|
fdMatches = data.matches ?? []
|
||||||
|
} catch {
|
||||||
|
return NextResponse.json({ error: 'No se pudo conectar con la API externa' }, { status: 502 })
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json({ ok: true, message: 'Endpoint listo. Configurar RESULTS_API_URL para activar sync.' })
|
// Precargar equipos una sola vez
|
||||||
|
const teams = await prisma.team.findMany()
|
||||||
|
const teamByShortName = Object.fromEntries(teams.map(t => [t.shortName, t]))
|
||||||
|
|
||||||
|
let updated = 0
|
||||||
|
let skipped = 0
|
||||||
|
|
||||||
|
for (const fdMatch of fdMatches) {
|
||||||
|
const newStatus = mapStatus(fdMatch.status)
|
||||||
|
if (newStatus === 'SCHEDULED') { skipped++; continue }
|
||||||
|
|
||||||
|
const homeTla = fdMatch.homeTeam?.tla
|
||||||
|
const awayTla = fdMatch.awayTeam?.tla
|
||||||
|
if (!homeTla || !awayTla) { skipped++; continue }
|
||||||
|
|
||||||
|
const homeTeam = teamByShortName[homeTla]
|
||||||
|
const awayTeam = teamByShortName[awayTla]
|
||||||
|
if (!homeTeam || !awayTeam) { skipped++; continue }
|
||||||
|
|
||||||
|
const match = await prisma.match.findFirst({
|
||||||
|
where: { homeTeamId: homeTeam.id, awayTeamId: awayTeam.id },
|
||||||
|
})
|
||||||
|
if (!match) { skipped++; continue }
|
||||||
|
|
||||||
|
// Evitar re-procesar partidos ya finalizados
|
||||||
|
if (match.status === 'FINISHED' && newStatus === 'FINISHED') { skipped++; continue }
|
||||||
|
|
||||||
|
const homeScore = fdMatch.score.fullTime.home
|
||||||
|
const awayScore = fdMatch.score.fullTime.away
|
||||||
|
|
||||||
|
const updatedMatch = await prisma.match.update({
|
||||||
|
where: { id: match.id },
|
||||||
|
data: {
|
||||||
|
status: newStatus,
|
||||||
|
...(homeScore !== null && { homeScore }),
|
||||||
|
...(awayScore !== null && { awayScore }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (newStatus === 'FINISHED' && homeScore !== null && awayScore !== null) {
|
||||||
|
const predictions = await prisma.prediction.findMany({ where: { matchId: match.id } })
|
||||||
|
await Promise.all(
|
||||||
|
predictions.map(p =>
|
||||||
|
prisma.prediction.update({
|
||||||
|
where: { id: p.id },
|
||||||
|
data: { points: calculatePoints(p.result as 'HOME' | 'DRAW' | 'AWAY', homeScore, awayScore) },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
updated++
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json({ ok: true, updated, skipped, total: fdMatches.length })
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user