using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Shogi.Api.Extensions; using Shogi.Api.Managers; using Shogi.Api.Repositories; using Shogi.Contracts.Api; using Shogi.Contracts.Socket; using Shogi.Contracts.Types; using System.Data.SqlClient; namespace Shogi.Api.Controllers; [ApiController] [Route("[controller]")] [Authorize] public class SessionsController : ControllerBase { private readonly ISocketConnectionManager communicationManager; private readonly IModelMapper mapper; private readonly ISessionRepository sessionRepository; private readonly IQueryRespository queryRespository; private readonly ILogger logger; public SessionsController( ISocketConnectionManager communicationManager, IModelMapper mapper, ISessionRepository sessionRepository, IQueryRespository queryRespository, ILogger logger) { this.communicationManager = communicationManager; this.mapper = mapper; this.sessionRepository = sessionRepository; this.queryRespository = queryRespository; this.logger = logger; } [HttpPost] public async Task CreateSession([FromBody] CreateSessionCommand request) { var userId = User.GetShogiUserId(); var session = new Domain.Session(request.Name, userId); try { await sessionRepository.CreateSession(session); } catch (SqlException e) { logger.LogError(exception: e, message: "Uh oh"); return this.Conflict(); } await communicationManager.BroadcastToAll(new SessionCreatedSocketMessage()); return CreatedAtAction(nameof(CreateSession), new { sessionName = request.Name }, null); } [HttpDelete("{name}")] public async Task DeleteSession(string name) { var userId = User.GetShogiUserId(); var session = await sessionRepository.ReadSession(name); if (session == null) return this.NoContent(); if (session.Player1 == userId) { await sessionRepository.DeleteSession(name); return this.NoContent(); } return this.Forbid("Cannot delete sessions created by others."); } [HttpGet("PlayerCount")] public async Task> GetSessionsPlayerCount() { var sessions = await this.queryRespository.ReadSessionPlayerCount(); return Ok(new ReadSessionsPlayerCountResponse { PlayerHasJoinedSessions = Array.Empty(), AllOtherSessions = sessions.ToList() }); } [HttpGet("{name}")] public async Task> GetSession(string name) { var session = await sessionRepository.ReadSession(name); if (session == null) return this.NotFound(); return new ReadSessionResponse { Session = new Session { BoardState = new BoardState { Board = session.Board.BoardState.State.ToContract(), Player1Hand = session.Board.BoardState.Player1Hand.ToContract(), Player2Hand = session.Board.BoardState.Player2Hand.ToContract(), PlayerInCheck = session.Board.BoardState.InCheck?.ToContract(), WhoseTurn = session.Board.BoardState.WhoseTurn.ToContract() }, Player1 = session.Player1, Player2 = session.Player2, SessionName = session.Name } }; } [HttpPatch("{name}/Move")] public async Task Move([FromRoute] string name, [FromBody] MovePieceCommand command) { var userId = User.GetShogiUserId(); var session = await sessionRepository.ReadSession(name); if (session == null) return this.NotFound("Shogi session does not exist."); if (!session.IsSeated(userId)) return this.Forbid("Player is not a member of the Shogi session."); try { if (command.PieceFromHand.HasValue) { session.Board.Move(command.PieceFromHand.Value.ToDomain(), command.To); } else { session.Board.Move(command.From!, command.To, command.IsPromotion!.Value); } } catch (InvalidOperationException) { return this.Conflict("Move is illegal."); } // TODO: sessionRespository.SaveMove(); await communicationManager.BroadcastToPlayers( new PlayerHasMovedMessage { PlayerName = userId, SessionName = session.Name, }, session.Player1, session.Player2); return this.NoContent(); } //[HttpPost("{sessionName}/Move")] //public async Task MovePiece([FromRoute] string sessionName, [FromBody] MovePieceCommand request) //{ // var user = await gameboardManager.ReadUser(User); // var session = await gameboardRepository.ReadSession(sessionName); // if (session == null) // { // return NotFound(); // } // if (user == null || (session.Player1 != user.Id && session.Player2 != user.Id)) // { // return Forbid("User is not seated at this game."); // } // try // { // var move = request.Move; // if (move.PieceFromCaptured.HasValue) // session.Move(mapper.Map(move.PieceFromCaptured.Value), move.To); // else if (!string.IsNullOrWhiteSpace(move.From)) // session.Move(move.From, move.To, move.IsPromotion); // await gameboardRepository.CreateBoardState(session); // await communicationManager.BroadcastToPlayers( // new MoveResponse // { // SessionName = session.Name, // PlayerName = user.Id // }, // session.Player1, // session.Player2); // return Ok(); // } // catch (InvalidOperationException ex) // { // return Conflict(ex.Message); // } //} //[HttpPut("{sessionName}")] //public async Task PutJoinSession([FromRoute] string sessionName) //{ // var user = await ReadUserOrThrow(); // var session = await gameboardRepository.ReadSessionMetaData(sessionName); // if (session == null) // { // return NotFound(); // } // if (session.Player2 != null) // { // return this.Conflict("This session already has two seated players and is full."); // } // session.SetPlayer2(user.Id); // await gameboardRepository.UpdateSession(session); // var opponentName = user.Id == session.Player1 // ? session.Player2! // : session.Player1; // await communicationManager.BroadcastToPlayers(new JoinSessionResponse // { // SessionName = session.Name, // PlayerName = user.Id // }, opponentName); // return Ok(); //} }