oddsService = $oddsService; $this->betService = $betService; $this->scheduleService = $scheduleService; $this->settlementService = $settlementService; } public function odds(Request $request) { $filters = [ 'market' => (string)$request->input('market', ''), 'match_id' => (string)$request->input('match_id', ''), 'limit' => (int)$request->input('limit', 300), ]; if ($this->wantsJson($request)) { return $this->json(200, 'success', [ 'list' => $this->oddsService->listOdds($filters), ]); } return view('admin.world_cup.odds', [ 'filters' => $filters, 'odds' => $this->oddsService->listOdds($filters), 'matches' => $this->scheduleService->allMatches(), 'result' => $request->session()->get('world_cup_odds_result'), ]); } public function saveOdds(Request $request) { $result = $this->oddsService->saveOdds([ 'market' => (string)$request->input('market', ''), 'match_id' => $request->input('match_id') === '' ? null : $request->input('match_id'), 'selection' => (string)$request->input('selection', ''), 'decimal_odds' => (float)$request->input('decimal_odds', 0), 'is_active' => (int)$request->input('is_active', 0), 'locked_weight' => (int)$request->input('locked_weight', 0), ]); return $this->respond($request, $result, '/admin/world-cup/odds', 'world_cup_odds_result'); } public function importOdds(Request $request) { $rows = $this->parseCsvRows($request); $result = $rows === null ? [ 'success' => false, 'message' => 'Invalid CSV file', 'data' => [ 'updated' => 0, 'skipped' => 0, 'errors' => [], ], ] : $this->oddsService->importOddsRows( (string)$request->input('market', ''), $rows ); return $this->respond($request, $result, '/admin/world-cup/odds', 'world_cup_odds_result'); } public function bets(Request $request) { $result = $this->betService->adminBetLogs([ 'game_id' => $request->input('game_id', ''), 'user_id' => $request->input('user_id', ''), 'status' => $request->input('status', ''), 'market' => $request->input('market', ''), 'limit' => (int)$request->input('limit', 100), ]); if ($this->wantsJson($request)) { return $this->json(200, 'success', [ 'list' => $result['list'], ]); } return view('admin.world_cup.bets', [ 'filters' => $result['filters'], 'list' => $result['list'], ]); } public function settlement(Request $request) { if ($this->wantsJson($request)) { return $this->json(200, 'success', [ 'matches' => $this->scheduleService->allMatches(), ]); } return view('admin.world_cup.settlement', [ 'matches' => $this->scheduleService->allMatches(), 'result' => $request->session()->get('world_cup_settlement_result'), ]); } public function settleMatch(Request $request) { $result = $this->settlementService->settleMatch( (int)$request->input('match_id', 0), (string)$request->input('result', ''), $this->actor($request) ); return $this->respond($request, $result, '/admin/world-cup/settlement', 'world_cup_settlement_result'); } public function settleWinner(Request $request) { $result = $this->settlementService->settleWinner( (string)$request->input('selection', ''), $this->actor($request) ); return $this->respond($request, $result, '/admin/world-cup/settlement', 'world_cup_settlement_result'); } private function respond(Request $request, array $result, string $url, string $sessionKey) { if ($this->wantsJson($request)) { return $this->json($result['success'] ? 200 : 400, $result['message'] ?: 'success', $result['data']); } return redirect($url)->with($sessionKey, $result); } private function actor(Request $request): string { return (string)($request->session()->get('admin.username') ?: 'admin'); } private function wantsJson(Request $request): bool { return $request->ajax() || $request->expectsJson() || $request->input('format') === 'json'; } private function parseCsvRows(Request $request): ?array { if (!$request->hasFile('csv_file') || !$request->file('csv_file')->isValid()) { return null; } $handle = fopen($request->file('csv_file')->getRealPath(), 'r'); if ($handle === false) { return null; } $headers = null; $rows = []; while (($data = fgetcsv($handle)) !== false) { if ($headers === null) { $headers = $this->normalizeCsvHeaders($data); continue; } if ($this->isEmptyCsvRow($data)) { continue; } $values = array_slice(array_pad($data, count($headers), ''), 0, count($headers)); $rows[] = array_combine($headers, $values); } fclose($handle); return $headers === null ? null : $rows; } private function normalizeCsvHeaders(array $headers): array { return array_map(function ($header) { return trim(str_replace("\xEF\xBB\xBF", '', (string)$header)); }, $headers); } private function isEmptyCsvRow(array $row): bool { foreach ($row as $value) { if (trim((string)$value) !== '') { return false; } } return true; } }