package cache import ( "context" "encoding/json" "time" ) // PreferenceSavedCity represents a user's saved city preference. type PreferenceSavedCity struct { CityCode string `json:"city_code"` Name string `json:"name"` } // PreferenceSearchHistory represents a user's search history entry. type PreferenceSearchHistory struct { Query string `json:"query"` FromCity string `json:"from_city"` ToCity string `json:"to_city"` Date string `json:"date"` CreatedAt int64 `json:"created_at"` } // Preferences represents user preferences storage. // It provides methods for managing saved cities and search history. type Preferences struct { store Cache } // NewPreferences creates a new Preferences instance with the given cache store. func NewPreferences(store Cache) *Preferences { return &Preferences{store: store} } // GetSavedCities returns the user's saved cities. func (p *Preferences) GetSavedCities(ctx context.Context, userID string) ([]PreferenceSavedCity, error) { data, err := p.store.Get(ctx, &CacheKey{ Kind: "prefs:saved_city:" + userID, Code: userID, From: "", To: "", Date: "", Request: "", }) if err != nil { return nil, err } if data == nil { return []PreferenceSavedCity{}, nil } var cities []PreferenceSavedCity if err := json.Unmarshal(data, &cities); err != nil { return nil, err } return cities, nil } // AddSavedCity adds a city to the user's saved cities. func (p *Preferences) AddSavedCity(ctx context.Context, userID, cityCode, cityName string) error { // Load existing cities cities, err := p.GetSavedCities(ctx, userID) if err != nil { return err } // Check if city already exists exists := false for i, c := range cities { if c.CityCode == cityCode { cities[i].Name = cityName exists = true break } } if !exists { // Add new city cities = append(cities, PreferenceSavedCity{ CityCode: cityCode, Name: cityName, }) } // Store back to cache data, err := json.Marshal(cities) if err != nil { return err } cacheKey := &CacheKey{ Kind: "prefs:saved_city:" + userID, Code: userID, From: "", To: "", Date: "", Request: "", } if err := p.store.Set(ctx, cacheKey, data, PreferenceTTL); err != nil { return err } return nil } // RemoveSavedCity removes a city from the user's saved cities. func (p *Preferences) RemoveSavedCity(ctx context.Context, userID, cityCode string) error { // Load existing cities cities, err := p.GetSavedCities(ctx, userID) if err != nil { return err } // Remove the city var result []PreferenceSavedCity for _, c := range cities { if c.CityCode != cityCode { result = append(result, c) } } if len(result) == 0 { // If no cities left, delete the key key := &CacheKey{ Kind: "prefs:saved_city:" + userID, Code: userID, } return p.store.Delete(ctx, key) } // Store back data, err := json.Marshal(result) if err != nil { return err } key := &CacheKey{ Kind: "prefs:saved_city:" + userID, Code: userID, } return p.store.Set(ctx, key, data, PreferenceTTL) } // GetSearchHistory returns the user's search history. func (p *Preferences) GetSearchHistory(ctx context.Context, userID string) ([]PreferenceSearchHistory, error) { key := &CacheKey{ Kind: "prefs:search_history:" + userID, Code: userID, From: "", To: "", Date: "", Request: "", } data, err := p.store.Get(ctx, key) if err != nil { return nil, err } if data == nil { return []PreferenceSearchHistory{}, nil } var history []PreferenceSearchHistory if err := json.Unmarshal(data, &history); err != nil { return nil, err } return history, nil } // AddSearchHistory adds a search to the user's history. func (p *Preferences) AddSearchHistory(ctx context.Context, userID, fromCity, toCity, date string) error { key := &CacheKey{ Kind: "prefs:search_history:" + userID, Code: userID, From: "", To: "", Date: "", Request: "", } // Load existing history history, err := p.GetSearchHistory(ctx, userID) if err != nil { return err } // Add new entry at the beginning (most recent first) history = append([]PreferenceSearchHistory{ { Query: fromCity + "→" + toCity, FromCity: fromCity, ToCity: toCity, Date: date, CreatedAt: time.Now().Unix(), }, }, history...) // Keep only last 50 searches if len(history) > 50 { history = history[:50] } // Store back to cache data, err := json.Marshal(history) if err != nil { return err } if err := p.store.Set(ctx, key, data, PreferenceTTL); err != nil { return err } return nil } // RemoveOldSearchHistory removes search entries older than the given age. func (p *Preferences) RemoveOldSearchHistory(ctx context.Context, userID string, maxAgeSeconds int64) error { key := &CacheKey{ Kind: "prefs:search_history:" + userID, Code: userID, From: "", To: "", Date: "", Request: "", } history, err := p.GetSearchHistory(ctx, userID) if err != nil { return err } // Filter out old entries var recent []PreferenceSearchHistory now := time.Now().Unix() for _, entry := range history { if entry.CreatedAt >= now-maxAgeSeconds { recent = append(recent, entry) } } if len(recent) == len(history) { // No entries removed return nil } // Store back data, err := json.Marshal(recent) if err != nil { return err } if err := p.store.Set(ctx, key, data, PreferenceTTL); err != nil { return err } return nil }