using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Shogi.Api.Controllers; using Shogi.Api.Extensions; using Shogi.Api.Identity; using Shogi.Api.Repositories; using Shogi.Api.Repositories.Dto; using Shogi.Contracts.Api; using Shogi.Domain.Aggregates; using System.Data.SqlClient; namespace Shogi.Api.Application; public class ShogiApplication( QueryRepository queryRepository, SessionRepository sessionRepository, UserManager userManager, GameHubContext gameHubContext) { public async Task CreateSession(string playerId) { var session = new Session(Guid.NewGuid(), playerId); try { await sessionRepository.CreateSession(session); return new CreatedAtActionResult( nameof(SessionsController.GetSession), null, new { sessionId = session.Id.ToString() }, session.Id.ToString()); } catch (SqlException) { return new ConflictResult(); } } public async Task> ReadAllSessionMetadatas(string playerId) { return await queryRepository.ReadSessionsMetadata(playerId); } public async Task ReadSession(string id) { var (sessionDto, moveDtos) = await sessionRepository.ReadSessionAndMoves(id); if (!sessionDto.HasValue) { return null; } var session = new Session(Guid.Parse(sessionDto.Value.Id), sessionDto.Value.Player1Id); if (!string.IsNullOrWhiteSpace(sessionDto.Value.Player2Id)) session.AddPlayer2(sessionDto.Value.Player2Id); foreach (var move in moveDtos) { if (move.PieceFromHand.HasValue) { session.Board.Move(move.PieceFromHand.Value, move.To); } else if (move.From != null && move.IsPromotion.HasValue) { session.Board.Move(move.From, move.To, move.IsPromotion.Value); } else { throw new InvalidOperationException($"Corrupt data during {nameof(ReadSession)}"); } } return session; } public async Task MovePiece(string playerId, string sessionId, MovePieceCommand command) { var session = await this.ReadSession(sessionId); if (session == null) { return new NotFoundResult(); } if (!session.IsSeated(playerId)) { return new ForbidResult(); } try { if (command.PieceFromHand.HasValue) { session.Board.Move(command.PieceFromHand.Value.ToDomain(), command.To); } else { var isPromotion = command.IsPromotion ?? false; session.Board.Move(command.From!, command.To, isPromotion); } } catch (InvalidOperationException e) { return new ConflictObjectResult(e.Message); } await sessionRepository.CreateMove(sessionId, command); await gameHubContext.Emit_PieceMoved(sessionId); return new NoContentResult(); } public async Task JoinSession(string sessionId, string player2Id) { var session = await this.ReadSession(sessionId); if (session == null) return new NotFoundResult(); if (string.IsNullOrEmpty(session.Player2)) { session.AddPlayer2(player2Id); await sessionRepository.SetPlayer2(sessionId, player2Id); await gameHubContext.Emit_SessionJoined(sessionId); return new OkResult(); } return new ConflictObjectResult("This game already has two players."); } public string GetUsername(string? userId) { if (string.IsNullOrEmpty(userId)) { return string.Empty; } return userManager.Users.FirstOrDefault(u => u.Id == userId)?.UserName!; } }