package httpapi

import (
	"encoding/json"
	"os"
	"path/filepath"
)

// filePlayerStatusStore wraps inMemoryPlayerStatusStore and persists the
// records to a JSON file on every mutation. Reads are served from memory.
type filePlayerStatusStore struct {
	*inMemoryPlayerStatusStore
	path string
}

func newFilePlayerStatusStore(path string) (*filePlayerStatusStore, error) {
	s := &filePlayerStatusStore{
		inMemoryPlayerStatusStore: newInMemoryPlayerStatusStore(),
		path:                      path,
	}
	if err := s.load(); err != nil {
		return nil, err
	}
	return s, nil
}

// NewStoreFromConfig returns a playerStatusStore. If path is non-empty a
// file-backed store is used; otherwise an in-memory store is returned.
func NewStoreFromConfig(path string) (playerStatusStore, error) {
	if path == "" {
		return newInMemoryPlayerStatusStore(), nil
	}
	return newFilePlayerStatusStore(path)
}

func (s *filePlayerStatusStore) Save(record playerStatusRecord) {
	s.inMemoryPlayerStatusStore.Save(record)
	_ = s.persist()
}

func (s *filePlayerStatusStore) Delete(screenID string) bool {
	ok := s.inMemoryPlayerStatusStore.Delete(screenID)
	if ok {
		_ = s.persist()
	}
	return ok
}

func (s *filePlayerStatusStore) load() error {
	data, err := os.ReadFile(s.path)
	if os.IsNotExist(err) {
		return nil
	}
	if err != nil {
		return err
	}

	var records []playerStatusRecord
	if err := json.Unmarshal(data, &records); err != nil {
		return err
	}

	s.mu.Lock()
	defer s.mu.Unlock()
	for _, r := range records {
		s.records[r.ScreenID] = r
	}
	return nil
}

func (s *filePlayerStatusStore) persist() error {
	s.mu.RLock()
	records := make([]playerStatusRecord, 0, len(s.records))
	for _, r := range s.records {
		records = append(records, r)
	}
	s.mu.RUnlock()

	data, err := json.Marshal(records)
	if err != nil {
		return err
	}

	tmp := s.path + ".tmp"
	if err := os.WriteFile(tmp, data, 0o644); err != nil {
		return err
	}
	return os.Rename(tmp, filepath.Clean(s.path))
}
