package app

import (
	"fmt"
	"encoding/json"
	"os"
	"path/filepath"
	"sort"
	"sync"
	"time"

	"vrc_osc_go/internal/common"
)

type GuestStatus struct {
	Name      string    `json:"name"`
	Present   bool      `json:"present"`
	LastJoin  time.Time `json:"last_join"`
	LastLeave time.Time `json:"last_leave"`
	AbsentFor string    `json:"absent_for"`
}

type GuestTracker struct {
	mu      sync.RWMutex
	current string
	items   map[string]*GuestStatus
}

func NewGuestTracker(names []string) *GuestTracker {
	items := make(map[string]*GuestStatus, len(names))
	for _, name := range names {
		items[name] = &GuestStatus{Name: name}
	}
	return &GuestTracker{items: items}
}

func (t *GuestTracker) SetCurrentInstance(label string) {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.current = label
}

func (t *GuestTracker) CurrentInstance() string {
	t.mu.RLock()
	defer t.mu.RUnlock()
	return t.current
}

func (t *GuestTracker) MarkJoin(name string, at time.Time) {
	t.mu.Lock()
	defer t.mu.Unlock()
	s := t.ensure(name)
	s.Present = true
	s.LastJoin = at
	s.AbsentFor = ""
	_ = t.persistLocked()
}

func (t *GuestTracker) MarkLeave(name string, at time.Time) {
	t.mu.Lock()
	defer t.mu.Unlock()
	s := t.ensure(name)
	s.Present = false
	s.LastLeave = at
	if !s.LastJoin.IsZero() {
		s.AbsentFor = humanSince(at)
	}
	_ = t.persistLocked()
}

func (t *GuestTracker) Snapshot(now time.Time) []GuestStatus {
	t.mu.RLock()
	defer t.mu.RUnlock()
	out := make([]GuestStatus, 0, len(t.items))
	for _, s := range t.items {
		cp := *s
		if !cp.Present && !cp.LastLeave.IsZero() {
			cp.AbsentFor = humanSince(cp.LastLeave, now)
		}
		out = append(out, cp)
	}
	sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name })
	return out
}

func (t *GuestTracker) persistLocked() error {
	dir := filepath.Join(common.RootDir(), "runtime")
	if err := os.MkdirAll(dir, 0o755); err != nil {
		return err
	}
	snapshot := make([]GuestStatus, 0, len(t.items))
	for _, s := range t.items {
		cp := *s
		snapshot = append(snapshot, cp)
	}
	f, err := os.Create(filepath.Join(dir, "guest_snapshot.json"))
	if err != nil {
		return err
	}
	defer f.Close()
	enc := json.NewEncoder(f)
	enc.SetIndent("", "  ")
	return enc.Encode(snapshot)
}

func (t *GuestTracker) ensure(name string) *GuestStatus {
	if s, ok := t.items[name]; ok {
		return s
	}
	s := &GuestStatus{Name: name}
	t.items[name] = s
	return s
}

func humanSince(at time.Time, now ...time.Time) string {
	ref := time.Now()
	if len(now) > 0 {
		ref = now[0]
	}
	if at.IsZero() {
		return ""
	}
	d := ref.Sub(at)
	if d < time.Minute {
		return "1分未満"
	}
	m := int(d.Minutes())
	if m < 60 {
		return fmt.Sprintf("%d分前", m)
	}
	h := m / 60
	if h < 24 {
		return fmt.Sprintf("%d時間前", h)
	}
	return fmt.Sprintf("%d日前", h/24)
}
