package game_service import ( "context" "evening_detective_server/internal/modules/password_generator" "evening_detective_server/internal/modules/storytelling" "evening_detective_server/internal/repos/actions_repo" "evening_detective_server/internal/repos/applications_repo" "evening_detective_server/internal/repos/games_repo" "evening_detective_server/internal/repos/scenarios_repo" "evening_detective_server/internal/repos/teams_repo" "evening_detective_server/internal/services/scenarios_service" "time" ) type GameService struct { gamesRepo *games_repo.GamesRepo teamsRepo *teams_repo.TeamsRepo scenariosRepo *scenarios_repo.ScenariosRepo scenarioService *scenarios_service.ScenarioService domain string passwordGenerator password_generator.IPasswordGenerator storyteller storytelling.IStory actionsRepo *actions_repo.ActionsRepo applicationsRepo *applications_repo.ApplicationsRepo } func NewGameService( gamesRepo *games_repo.GamesRepo, teamsRepo *teams_repo.TeamsRepo, scenariosRepo *scenarios_repo.ScenariosRepo, scenarioService *scenarios_service.ScenarioService, domain string, passwordGenerator password_generator.IPasswordGenerator, storyteller storytelling.IStory, actionsRepo *actions_repo.ActionsRepo, applicationsRepo *applications_repo.ApplicationsRepo, ) *GameService { return &GameService{ gamesRepo: gamesRepo, teamsRepo: teamsRepo, scenariosRepo: scenariosRepo, scenarioService: scenarioService, domain: domain, passwordGenerator: passwordGenerator, storyteller: storyteller, actionsRepo: actionsRepo, applicationsRepo: applicationsRepo, } } func (s *GameService) AddGame( ctx context.Context, name string, description string, startAt time.Time, scenarioId int32, ) (int, error) { id, err := s.gamesRepo.AddGame(ctx, name, description, startAt, scenarioId) if err != nil { return 0, err } return id, nil } func (s *GameService) GetGame( ctx context.Context, id int, ) (*Game, error) { game, err := s.gamesRepo.GetGameByID(ctx, id) if err != nil { return nil, err } scenario, err := s.scenariosRepo.GetScenarioByID(ctx, game.ScenarioId) if err != nil { return nil, err } game.Scenario = scenario teams, err := s.teamsRepo.GetTeamsByGameID(ctx, id) if err != nil { return nil, err } game.Teams = teams res := mapGame(game, s.domain) teamIds := make([]int, 0, len(game.Teams)) for _, team := range game.Teams { teamIds = append(teamIds, team.ID) } actionsCountByTeamIDs, err := s.actionsRepo.GetActionsCountByTeamIDs(ctx, teamIds) if err != nil { return nil, err } needApplicationsByTeamIDs, err := s.applicationsRepo.GetApplicationsByTeamIDsAndState(ctx, teamIds, "need") if err != nil { return nil, err } for _, team := range res.Teams { team.ActionsCount = actionsCountByTeamIDs[team.ID] team.Applications = mapApplications(needApplicationsByTeamIDs[team.ID]) } return res, nil } func (s *GameService) DeleteGame( ctx context.Context, id int, ) error { return s.gamesRepo.DeleteGameByID(ctx, id) } func (s *GameService) GetGames( ctx context.Context, ) ([]*Game, error) { games, err := s.gamesRepo.GetGames(ctx) if err != nil { return nil, err } return mapGames(games, s.domain), nil } func (s *GameService) UpdateGame( ctx context.Context, id int, name string, description string, startAt time.Time, scenarioId int32, ) error { return s.gamesRepo.UpdateGame(ctx, id, name, description, startAt, scenarioId) } func (s *GameService) AddTeam( ctx context.Context, creatorId int, gameId int, name string, ) (*Team, error) { game, err := s.gamesRepo.GetGameByID(ctx, gameId) if err != nil { return nil, err } password, err := s.passwordGenerator.Generate() if err != nil { return nil, err } id, err := s.teamsRepo.AddTeam(ctx, creatorId, gameId, name, game.ScenarioId, password) if err != nil { return nil, err } return &Team{ ID: id, Password: password, }, nil } func (s *GameService) UpdateTeam(ctx context.Context, teamId int, name string) error { return s.teamsRepo.UpdateTeam(ctx, teamId, name) } func (s *GameService) DeleteTeam(ctx context.Context, teamId int) error { return s.teamsRepo.DeleteTeam(ctx, teamId) } func (s *GameService) GiveTeamApplications(ctx context.Context, teamId int, name string) error { return s.applicationsRepo.UpdateApplicationStatus(ctx, teamId, name, "done") } func (s *GameService) GetTeamActions(ctx context.Context, teamId int, password string) (*storytelling.Story, error) { team, err := s.teamsRepo.GetTeamByID(ctx, teamId) if err != nil { return nil, err } if team.Password != password { return nil, teams_repo.ErrTeamNotFound } actions, err := s.actionsRepo.GetActionsByTeamID(ctx, teamId) if err != nil { return nil, err } scenario, err := s.scenarioService.GetFullScenarioByID(ctx, team.ScenarioId) if err != nil { return nil, err } return s.storyteller.GetStory(scenario.Story, actions), nil } func (s *GameService) AddTeamAction(ctx context.Context, teamId int, password string, actionCode string) error { team, err := s.teamsRepo.GetTeamByID(ctx, teamId) if err != nil { return err } if team.Password != password { return teams_repo.ErrTeamNotFound } _, err = s.actionsRepo.AddAction(ctx, teamId, actionCode) if err != nil { return err } actions, err := s.actionsRepo.GetActionsByTeamID(ctx, teamId) if err != nil { return err } scenario, err := s.scenarioService.GetFullScenarioByID(ctx, team.ScenarioId) if err != nil { return err } teamStory := s.storyteller.GetStory(scenario.Story, actions) lastPlace := teamStory.Places[len(teamStory.Places)-1] for _, application := range lastPlace.Applications { _, err := s.applicationsRepo.AddApplication(ctx, teamId, application.Name, application.Image) if err != nil { return err } } return nil } func (s *GameService) DeleteLastTeamAction(ctx context.Context, teamId int) error { team, err := s.teamsRepo.GetTeamByID(ctx, teamId) if err != nil { return err } actions, err := s.actionsRepo.GetActionsByTeamID(ctx, teamId) if err != nil { return err } scenario, err := s.scenarioService.GetFullScenarioByID(ctx, team.ScenarioId) if err != nil { return err } teamStory := s.storyteller.GetStory(scenario.Story, actions) lastPlace := teamStory.Places[len(teamStory.Places)-1] for _, application := range lastPlace.Applications { if err := s.applicationsRepo.DeleteApplicationByTeamIdAndName(ctx, teamId, application.Name); err != nil { return err } } return s.actionsRepo.DeleteLastActionByTeamId(ctx, teamId) }