// 2026 글로벌 축구 축전 Group A 정식 일정 (출처: Wikipedia, KST 변환 검증 2026-06-08) // 모든 kickoffKst는 한국시간(+09:00). lockAt = 킥오프 -10분. import type { Match, Team } from "./types"; const KOR: Team = { name: "Korea Republic", shortName: "한국", code: "KOR", flag: "🇰🇷" }; const CZE: Team = { name: "Czechia", shortName: "체코", code: "CZE", flag: "🇨🇿" }; const MEX: Team = { name: "Mexico", shortName: "멕시코", code: "MEX", flag: "🇲🇽" }; const RSA: Team = { name: "South Africa", shortName: "남아공", code: "RSA", flag: "🇿🇦" }; // 투표 오픈 = 킥오프 -48시간 (D-2). 마감 = 킥오프 정각(경기 시작 전까지). function opens(iso: string): string { return new Date(new Date(iso).getTime() - 48 * 3600000).toISOString(); } // Group A 전체 6경기 — 경기별 정확 일시 자동 반영용 SSOT export const GROUP_A: Match[] = [ { matchId: "A_MEX_RSA_20260612", roundLabel: "Match 01 · 개막전", group: "A", teamA: MEX, teamB: RSA, kickoffKst: "2026-06-12T04:00:00+09:00", venue: "Estadio Azteca · Mexico City", opensAt: opens("2026-06-12T04:00:00+09:00"), lockAt: "2026-06-12T04:00:00+09:00", status: "upcoming", hookText: "글로벌 축구 개막전, AI는 개최국을 믿을까", result: null, }, { matchId: "A_KOR_CZE_20260612", roundLabel: "Match 01", group: "A", teamA: KOR, teamB: CZE, kickoffKst: "2026-06-12T11:00:00+09:00", venue: "Estadio Guadalajara (Akron)", opensAt: opens("2026-06-12T11:00:00+09:00"), lockAt: "2026-06-12T11:00:00+09:00", status: "upcoming", hookText: "한국 첫 경기, AI의 선택은 갈렸다", result: null, }, { matchId: "A_CZE_RSA_20260619", roundLabel: "Match 02", group: "A", teamA: CZE, teamB: RSA, kickoffKst: "2026-06-19T01:00:00+09:00", venue: "USA (TBD)", opensAt: opens("2026-06-19T01:00:00+09:00"), lockAt: "2026-06-19T01:00:00+09:00", status: "upcoming", hookText: "체코 vs 남아공, AI의 예측은", result: null, }, { matchId: "A_MEX_KOR_20260619", roundLabel: "Match 02", group: "A", teamA: MEX, teamB: KOR, kickoffKst: "2026-06-19T10:00:00+09:00", venue: "Estadio Guadalajara (Akron)", opensAt: opens("2026-06-19T10:00:00+09:00"), lockAt: "2026-06-19T10:00:00+09:00", status: "upcoming", hookText: "개최국 멕시코 vs 한국, AI는 누구 편", result: null, }, { matchId: "A_CZE_MEX_20260625", roundLabel: "Match 03", group: "A", teamA: CZE, teamB: MEX, kickoffKst: "2026-06-25T10:00:00+09:00", venue: "Estadio Azteca · Mexico City", opensAt: opens("2026-06-25T10:00:00+09:00"), lockAt: "2026-06-25T10:00:00+09:00", status: "upcoming", hookText: "체코 vs 멕시코, 운명의 최종전", result: null, }, { matchId: "A_RSA_KOR_20260625", roundLabel: "Match 03", group: "A", teamA: RSA, teamB: KOR, kickoffKst: "2026-06-25T10:00:00+09:00", venue: "Estadio BBVA · Monterrey", opensAt: opens("2026-06-25T10:00:00+09:00"), lockAt: "2026-06-25T10:00:00+09:00", status: "upcoming", hookText: "한국 16강의 갈림길, AI의 마지막 예측", result: null, }, ]; // 현재 노출할 대표 경기 (체코전) export const FEATURED_MATCH_ID = "A_KOR_CZE_20260612"; export function getMatch(id: string): Match { return GROUP_A.find((m) => m.matchId === id) ?? GROUP_A[1]; } export const FEATURED = getMatch(FEATURED_MATCH_ID); // 투표창 단계(D7): 오픈 전 / 투표중 / 마감(킥오프) / 종료(결과). DEMO_FORCE_OPEN는 UI 측에서 별도 처리. export type MatchPhase = "scheduled" | "open" | "locked" | "finished"; export function matchPhase(m: Match, now: number = Date.now()): MatchPhase { if (m.result) return "finished"; if (now >= new Date(m.lockAt).getTime()) return "locked"; if (now < new Date(m.opensAt).getTime()) return "scheduled"; return "open"; } // 대시보드: 날짜별로 묶고 킥오프 오름차순 정렬 export function matchesByDate(): { date: string; matches: Match[] }[] { const sorted = [...GROUP_A].sort( (a, b) => new Date(a.kickoffKst).getTime() - new Date(b.kickoffKst).getTime(), ); const groups: { date: string; matches: Match[] }[] = []; for (const m of sorted) { const key = m.kickoffKst.slice(0, 10); const last = groups[groups.length - 1]; if (last && last.date === key) last.matches.push(m); else groups.push({ date: key, matches: [m] }); } return groups; }