package httpapi

import (
	"sort"
	"sync"
	"time"
)

type playerStatusRecord struct {
	ScreenID              string `json:"screen_id"`
	Timestamp             string `json:"ts"`
	Status                string `json:"status"`
	ServerConnectivity    string `json:"server_connectivity,omitempty"`
	ReceivedAt            string `json:"received_at,omitempty"`
	Stale                 bool   `json:"stale,omitempty"`
	DerivedState          string `json:"derived_state,omitempty"`
	ServerURL             string `json:"server_url,omitempty"`
	MQTTBroker            string `json:"mqtt_broker,omitempty"`
	HeartbeatEverySeconds int    `json:"heartbeat_every_seconds,omitempty"`
	StartedAt             string `json:"started_at,omitempty"`
	LastHeartbeatAt       string `json:"last_heartbeat_at,omitempty"`
}

type playerStatusStore interface {
	Save(record playerStatusRecord)
	Get(screenID string) (playerStatusRecord, bool)
	List() []playerStatusRecord
	Now() time.Time
	Delete(screenID string) bool
}

type inMemoryPlayerStatusStore struct {
	mu      sync.RWMutex
	records map[string]playerStatusRecord
	now     func() time.Time
}

func newInMemoryPlayerStatusStore() *inMemoryPlayerStatusStore {
	return &inMemoryPlayerStatusStore{records: make(map[string]playerStatusRecord), now: time.Now}
}

func NewPlayerStatusStore() playerStatusStore {
	return newInMemoryPlayerStatusStore()
}

func (s *inMemoryPlayerStatusStore) Save(record playerStatusRecord) {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.now != nil && record.ReceivedAt == "" {
		record.ReceivedAt = s.now().Format(time.RFC3339)
	}
	s.records[record.ScreenID] = record
}

func (s *inMemoryPlayerStatusStore) Get(screenID string) (playerStatusRecord, bool) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	record, ok := s.records[screenID]
	return record, ok
}

func (s *inMemoryPlayerStatusStore) List() []playerStatusRecord {
	s.mu.RLock()
	defer s.mu.RUnlock()

	records := make([]playerStatusRecord, 0, len(s.records))
	for _, record := range s.records {
		records = append(records, record)
	}

	sort.Slice(records, func(i, j int) bool {
		return records[i].ScreenID < records[j].ScreenID
	})

	return records
}

func (s *inMemoryPlayerStatusStore) Delete(screenID string) bool {
	s.mu.Lock()
	defer s.mu.Unlock()
	_, ok := s.records[screenID]
	if ok {
		delete(s.records, screenID)
	}
	return ok
}

func (s *inMemoryPlayerStatusStore) Now() time.Time {
	if s.now == nil {
		return time.Now()
	}
	return s.now()
}
