package economy import "context" // LoadCatalog کاتالوگ را از دیتابیس خوانده و در حافظه کش می‌کند. // در شروع برنامه و پس از هر ویرایشِ ادمین فراخوانی می‌شود. func (s *Service) LoadCatalog(ctx context.Context) error { var c Catalog rows, err := s.db.QueryContext(ctx, `SELECT id, title, coins, vip_days, price_toman, bonus_pct FROM coin_packages WHERE enabled = 1 ORDER BY sort`) if err != nil { return err } for rows.Next() { var p CoinPackage if err := rows.Scan(&p.ID, &p.Title, &p.Coins, &p.VIPDays, &p.PriceToman, &p.BonusPct); err != nil { rows.Close() return err } c.CoinPackages = append(c.CoinPackages, p) } rows.Close() rows, err = s.db.QueryContext(ctx, `SELECT id, title, tickets, price_toman FROM ticket_packages WHERE enabled = 1 ORDER BY sort`) if err != nil { return err } for rows.Next() { var p TicketPackage if err := rows.Scan(&p.ID, &p.Title, &p.Tickets, &p.PriceToman); err != nil { rows.Close() return err } c.TicketPackages = append(c.TicketPackages, p) } rows.Close() rows, err = s.db.QueryContext(ctx, `SELECT id, title, price_coins FROM card_skins WHERE enabled = 1 ORDER BY sort`) if err != nil { return err } for rows.Next() { var p CardSkin if err := rows.Scan(&p.ID, &p.Title, &p.PriceCoins); err != nil { rows.Close() return err } c.CardSkins = append(c.CardSkins, p) } rows.Close() rows, err = s.db.QueryContext(ctx, `SELECT id, title, multiplier, hours, price_toman FROM boosters WHERE enabled = 1 ORDER BY sort`) if err != nil { return err } for rows.Next() { var p Booster if err := rows.Scan(&p.ID, &p.Title, &p.Multiplier, &p.Hours, &p.PriceToman); err != nil { rows.Close() return err } c.Boosters = append(c.Boosters, p) } rows.Close() rows, err = s.db.QueryContext(ctx, `SELECT id, title, months, price_toman FROM vip_packages WHERE enabled = 1 ORDER BY sort`) if err != nil { return err } for rows.Next() { var p VIPPackage if err := rows.Scan(&p.ID, &p.Title, &p.Months, &p.PriceToman); err != nil { rows.Close() return err } c.VIPPackages = append(c.VIPPackages, p) } rows.Close() rows, err = s.db.QueryContext(ctx, `SELECT id, title, hands, entry, prize, xp, trophy FROM table_tiers WHERE enabled = 1 ORDER BY sort`) if err != nil { return err } for rows.Next() { var p TableTier if err := rows.Scan(&p.ID, &p.Title, &p.Hands, &p.Entry, &p.Prize, &p.XP, &p.Trophy); err != nil { rows.Close() return err } c.TableTiers = append(c.TableTiers, p) } rows.Close() s.mu.Lock() s.cat = c s.mu.Unlock() return nil } // Catalog کپیِ کشِ فعلیِ کاتالوگ را برمی‌گرداند. func (s *Service) Catalog() Catalog { s.mu.RLock() defer s.mu.RUnlock() return s.cat } func (s *Service) findCoinPackage(id string) *CoinPackage { s.mu.RLock() defer s.mu.RUnlock() for i := range s.cat.CoinPackages { if s.cat.CoinPackages[i].ID == id { p := s.cat.CoinPackages[i] return &p } } return nil } func (s *Service) findTicketPackage(id string) *TicketPackage { s.mu.RLock() defer s.mu.RUnlock() for i := range s.cat.TicketPackages { if s.cat.TicketPackages[i].ID == id { p := s.cat.TicketPackages[i] return &p } } return nil } func (s *Service) findCardSkin(id string) *CardSkin { s.mu.RLock() defer s.mu.RUnlock() for i := range s.cat.CardSkins { if s.cat.CardSkins[i].ID == id { p := s.cat.CardSkins[i] return &p } } return nil } func (s *Service) findBooster(id string) *Booster { s.mu.RLock() defer s.mu.RUnlock() for i := range s.cat.Boosters { if s.cat.Boosters[i].ID == id { p := s.cat.Boosters[i] return &p } } return nil } func (s *Service) findVIPPackage(id string) *VIPPackage { s.mu.RLock() defer s.mu.RUnlock() for i := range s.cat.VIPPackages { if s.cat.VIPPackages[i].ID == id { p := s.cat.VIPPackages[i] return &p } } return nil } // FindTier نوع میز را از کش برمی‌گرداند (برای لایه بازی). func (s *Service) FindTier(id string) *TableTier { s.mu.RLock() defer s.mu.RUnlock() for i := range s.cat.TableTiers { if s.cat.TableTiers[i].ID == id { t := s.cat.TableTiers[i] return &t } } return nil }