with(["winner", "player1", "player2"]); if ($request->has("type")) { $query->where("type", $request->type); } if ($request->has("status")) { $query->where("status", $request->status); } if ($request->has("pot") && in_array($request->pot, ["asc", "desc"])) { $query->orderBy("stake", $request->pot); } elseif ( $request->has("sort_direction") && in_array($request->sort_direction, ["asc", "desc"]) ) { $query->orderBy("began_at", $request->sort_direction); } else { $query->orderBy("began_at", "desc"); } return response()->json($query->paginate(15)); } public function store(StoreMatchRequest $request) { $validated = $request->validated(); $user = $request->user(); $stake = $validated["stake"]; if ($user->coins_balance < $stake) { return response()->json( ["message" => "Insufficient coin balance"], 400, ); } $activeMatch = MatchGame::where(function ($q) use ($user) { $q->where("player1_user_id", $user->id)->orWhere( "player2_user_id", $user->id, ); }) ->whereIn("status", ["Pending", "Playing"]) ->exists(); if ($activeMatch) { return response()->json( ["message" => "You already have an active match."], 400, ); } return DB::transaction(function () use ($validated, $user, $stake) { $GHOST_ID = 1; $user->decrement("coins_balance", $stake); $stakeType = CoinTransactionType::firstOrCreate( ["name" => "Match stake"], ["type" => "D"], // Debit ); $match = MatchGame::create([ "type" => $validated["type"], "status" => "Pending", "player1_user_id" => $user->id, "player2_user_id" => $GHOST_ID, "winner_user_id" => $GHOST_ID, "loser_user_id" => $GHOST_ID, "stake" => $stake, "began_at" => now(), "player1_marks" => 0, "player2_marks" => 0, "player1_points" => 0, "player2_points" => 0, ]); CoinTransaction::create([ "user_id" => $user->id, "match_id" => $match->id, "coin_transaction_type_id" => $stakeType->id, "transaction_datetime" => now(), "coins" => -$stake, ]); return response()->json( [ "message" => "Match created successfully", "match" => $match, "balance" => $user->coins_balance, ], 201, ); }); } public function show(MatchGame $match) { $match->load(["player1", "player2", "winner"]); return response()->json($match); } public function join(MatchGame $match) { $user = request()->user(); if ($match->player1_user_id == $user->id) { return response()->json( ["message" => "You cannot join your own match"], 400, ); } if ($match->status !== "Pending") { return response()->json( ["message" => "Match is full or started"], 400, ); } if ($user->coins_balance < $match->stake) { return response()->json( ["message" => "Insufficient coin balance to join this match"], 400, ); } $activeMatch = MatchGame::where(function ($q) use ($user) { $q->where("player1_user_id", $user->id)->orWhere( "player2_user_id", $user->id, ); }) ->whereIn("status", ["Pending", "Playing"]) ->exists(); if ($activeMatch) { return response()->json( ["message" => "You are already in another active match."], 400, ); } return DB::transaction(function () use ($match, $user) { $user->decrement("coins_balance", $match->stake); $stakeType = CoinTransactionType::firstOrCreate( ["name" => "Match stake"], ["type" => "D"], ); CoinTransaction::create([ "user_id" => $user->id, "match_id" => $match->id, "coin_transaction_type_id" => $stakeType->id, "transaction_datetime" => now(), "coins" => -$match->stake, ]); $match->update([ "status" => "Playing", "player2_user_id" => $user->id, ]); return response()->json([ "message" => "Joined match successfully!", "match" => $match, "balance" => $user->coins_balance, ]); }); } public function update(Request $request, MatchGame $match) { if ($match->status == "Ended") { return response()->json(["message" => "Match already ended"], 400); } $data = $request->validate([ "status" => "in:Playing,Ended,Interrupted", "winner_user_id" => "exists:users,id", "loser_user_id" => "exists:users,id", "player1_marks" => "integer", "player2_marks" => "integer", "player1_points" => "integer", "player2_points" => "integer", "total_time" => "numeric", ]); return DB::transaction(function () use ($match, $data) { if (isset($data["status"]) && $data["status"] === "Ended") { $data["ended_at"] = now(); } $match->update($data); if ( $match->status === "Ended" && $match->stake > 0 && $match->winner_user_id ) { $payoutType = CoinTransactionType::firstOrCreate( ["name" => "Match payout"], ["type" => "C"], // Credit ); $totalPrize = $match->stake * 2; CoinTransaction::create([ "user_id" => $match->winner_user_id, "match_id" => $match->id, "coin_transaction_type_id" => $payoutType->id, "transaction_datetime" => now(), "coins" => $totalPrize, ]); $match->winner->increment("coins_balance", $totalPrize); } return response()->json($match); }); } public function host(Request $request) { $request->validate([ "type" => "required|in:3,9", "stake" => "required|integer|min:0", ]); $user = $request->user(); $stake = $request->stake; if ($user->coins_balance < $stake) { return response()->json( ["message" => "Insufficient coin balance"], 400, ); } $activeMatch = MatchGame::where(function ($q) use ($user) { $q->where("player1_user_id", $user->id)->orWhere( "player2_user_id", $user->id, ); }) ->whereIn("status", ["Pending", "Playing"]) ->exists(); if ($activeMatch) { return response()->json( ["message" => "You already have an active match."], 400, ); } return DB::transaction(function () use ($request, $user, $stake) { $GHOST_ID = 1; $user->decrement("coins_balance", $stake); $stakeType = CoinTransactionType::firstOrCreate( ["name" => "Match stake"], ["type" => "D"], // Debit ); $match = MatchGame::create([ "type" => $request->type, "status" => "Pending", "player1_user_id" => $user->id, "player2_user_id" => $GHOST_ID, "winner_user_id" => null, "loser_user_id" => null, "stake" => $stake, "began_at" => now(), "player1_marks" => 0, "player2_marks" => 0, "player1_points" => 0, "player2_points" => 0, ]); CoinTransaction::create([ "user_id" => $user->id, "match_id" => $match->id, "coin_transaction_type_id" => $stakeType->id, "transaction_datetime" => now(), "coins" => -$stake, ]); return response()->json($match, 201); }); } public function open(Request $request) { $type = $request->query("type", "9"); $GHOST_ID = 1; $matches = MatchGame::where("status", "Pending") ->where("player2_user_id", $GHOST_ID) ->where("type", $type) ->with("player1") ->orderBy("began_at", "asc") ->paginate(10); return response()->json($matches); } }