package services import ( "encoding/json" "fmt" "os" "path/filepath" "strings" "sync" "time" "arma3-web-server/internal/models" "github.com/google/uuid" ) type ModlistManager struct { dir string mu sync.RWMutex } func NewModlistManager(dataDir string) *ModlistManager { return &ModlistManager{ dir: filepath.Join(dataDir, "modlists"), } } func (mm *ModlistManager) path(id string) string { return filepath.Join(mm.dir, id+".json") } func (mm *ModlistManager) List() ([]models.ModlistListItem, error) { mm.mu.RLock() defer mm.mu.RUnlock() entries, err := os.ReadDir(mm.dir) if err != nil { if os.IsNotExist(err) { return []models.ModlistListItem{}, nil } return nil, err } var items []models.ModlistListItem for _, e := range entries { if e.IsDir() || !strings.HasSuffix(e.Name(), ".json") { continue } data, err := os.ReadFile(filepath.Join(mm.dir, e.Name())) if err != nil { continue } var m models.Modlist if err := json.Unmarshal(data, &m); err != nil { continue } items = append(items, models.ModlistListItem{ ID: m.ID, Name: m.Name, ModCount: len(m.Mods), CreatedAt: m.CreatedAt, UpdatedAt: m.UpdatedAt, }) } return items, nil } func (mm *ModlistManager) Get(id string) (*models.Modlist, error) { mm.mu.RLock() defer mm.mu.RUnlock() data, err := os.ReadFile(mm.path(id)) if err != nil { if os.IsNotExist(err) { return nil, fmt.Errorf("modlist not found") } return nil, err } var m models.Modlist if err := json.Unmarshal(data, &m); err != nil { return nil, err } return &m, nil } func (mm *ModlistManager) Create(name string) (*models.Modlist, error) { mm.mu.Lock() defer mm.mu.Unlock() now := time.Now().UTC() m := &models.Modlist{ ID: uuid.New().String(), Name: name, Mods: []models.ModEntry{}, CreatedAt: now, UpdatedAt: now, } data, err := json.MarshalIndent(m, "", " ") if err != nil { return nil, err } if err := os.MkdirAll(mm.dir, 0755); err != nil { return nil, err } if err := os.WriteFile(mm.path(m.ID), data, 0644); err != nil { return nil, err } return m, nil } func (mm *ModlistManager) Update(id, name string, mods []models.ModEntry) (*models.Modlist, error) { mm.mu.Lock() defer mm.mu.Unlock() m, err := mm.getLocked(id) if err != nil { return nil, err } m.Name = name m.Mods = mods m.UpdatedAt = time.Now().UTC() data, err := json.MarshalIndent(m, "", " ") if err != nil { return nil, err } if err := os.WriteFile(mm.path(id), data, 0644); err != nil { return nil, err } return m, nil } func (mm *ModlistManager) Delete(id string) error { mm.mu.Lock() defer mm.mu.Unlock() return os.Remove(mm.path(id)) } func (mm *ModlistManager) Duplicate(id, newName string) (*models.Modlist, error) { mm.mu.Lock() defer mm.mu.Unlock() orig, err := mm.getLocked(id) if err != nil { return nil, err } now := time.Now().UTC() dup := &models.Modlist{ ID: uuid.New().String(), Name: newName, Mods: orig.Mods, CreatedAt: now, UpdatedAt: now, } data, err := json.MarshalIndent(dup, "", " ") if err != nil { return nil, err } if err := os.WriteFile(mm.path(dup.ID), data, 0644); err != nil { return nil, err } return dup, nil } func (mm *ModlistManager) getLocked(id string) (*models.Modlist, error) { data, err := os.ReadFile(mm.path(id)) if err != nil { if os.IsNotExist(err) { return nil, fmt.Errorf("modlist not found") } return nil, err } var m models.Modlist if err := json.Unmarshal(data, &m); err != nil { return nil, err } return &m, nil }