package anime import ( "context" "mal/integrations/jikan" "mal/internal/db" "golang.org/x/sync/errgroup" ) type Service struct { jikanClient *jikan.Client db db.Querier } func NewService(jikanClient *jikan.Client, db db.Querier) *Service { return &Service{jikanClient: jikanClient, db: db} } // GetCatalogSection fetches homepage catalog sections (Airing, Popular, Continue) from jikan and db. func (s *Service) GetCatalogSection(ctx context.Context, userID string, section string) (map[string]any, error) { var ( res jikan.TopAnimeResult cw []db.GetContinueWatchingEntriesRow watchlist []db.GetUserWatchListRow err error ) g, gCtx := errgroup.WithContext(ctx) // fetch jikan data (season now or top anime) g.Go(func() error { switch section { case "Airing": res, err = s.jikanClient.GetSeasonsNow(gCtx, 1) case "Popular": res, err = s.jikanClient.GetTopAnime(gCtx, 1) } return err }) // fetch user-specific data if logged in if userID != "" { g.Go(func() error { if section == "Continue" { var err error cw, err = s.db.GetContinueWatchingEntries(gCtx, userID) return err } return nil }) g.Go(func() error { var err error watchlist, err = s.db.GetUserWatchList(gCtx, userID) return err }) } if err := g.Wait(); err != nil { return nil, err } // limit to 6 items for homepage grid animes := res.Animes if len(animes) > 6 { animes = animes[:6] } watchlistMap := make(map[int64]bool) for _, entry := range watchlist { watchlistMap[entry.AnimeID] = true } return map[string]any{ "Animes": animes, "ContinueWatching": cw, "WatchlistMap": watchlistMap, }, nil } // GetDiscoverSection fetches discover page sections (Trending, Upcoming, Top) from jikan. func (s *Service) GetDiscoverSection(ctx context.Context, userID string, section string) (map[string]any, error) { var ( res jikan.TopAnimeResult watchlist []db.GetUserWatchListRow err error ) g, gCtx := errgroup.WithContext(ctx) g.Go(func() error { switch section { case "Trending": res, err = s.jikanClient.GetSeasonsNow(gCtx, 1) case "Upcoming": res, err = s.jikanClient.GetSeasonsUpcoming(gCtx, 1) case "Top": res, err = s.jikanClient.GetTopAnime(gCtx, 1) } return err }) if userID != "" { g.Go(func() error { var err error watchlist, err = s.db.GetUserWatchList(gCtx, userID) return err }) } if err := g.Wait(); err != nil { return nil, err } // limit to 8 items for discover grid animes := res.Animes if len(animes) > 8 { animes = animes[:8] } watchlistMap := make(map[int64]bool) for _, entry := range watchlist { watchlistMap[entry.AnimeID] = true } return map[string]any{ "Animes": animes, "WatchlistMap": watchlistMap, }, nil }