package player

import (
	"os"
	"os/exec"
	"sync"
)

// Player handles alarm sound playback by shelling out to system audio tools.
type Player struct {
	mu      sync.Mutex
	cmd     *exec.Cmd
	playing bool
}

func New() *Player {
	return &Player{}
}

// Play starts playing a sound file. If path is "default", it uses a system beep.
func (p *Player) Play(path string) {
	p.mu.Lock()
	defer p.mu.Unlock()

	p.stop()

	if path == "default" || path == "" {
		// Try common system sounds, fall back to terminal bell
		candidates := []string{
			"/usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga",
			"/usr/share/sounds/gnome/default/alerts/bark.ogg",
			"/usr/share/sounds/sound-icons/trumpet-12.wav",
		}
		for _, c := range candidates {
			if _, err := os.Stat(c); err == nil {
				path = c
				break
			}
		}
		if path == "default" || path == "" {
			// No sound files found — use terminal bell in a loop
			go func() {
				for i := 0; i < 10; i++ {
					os.Stdout.WriteString("\a")
				}
			}()
			return
		}
	}

	// Try players in order of preference
	players := []struct {
		name string
		args func(string) []string
	}{
		{"paplay", func(f string) []string { return []string{f} }},
		{"aplay", func(f string) []string { return []string{f} }},
		{"mpv", func(f string) []string { return []string{"--no-video", "--loop=inf", f} }},
		{"ffplay", func(f string) []string { return []string{"-nodisp", "-autoexit", "-loop", "0", f} }},
	}

	for _, pl := range players {
		if _, err := exec.LookPath(pl.name); err == nil {
			p.cmd = exec.Command(pl.name, pl.args(path)...)
			p.cmd.Stdout = nil
			p.cmd.Stderr = nil
			p.playing = true
			go func() {
				_ = p.cmd.Run()
				p.mu.Lock()
				p.playing = false
				p.mu.Unlock()
			}()
			return
		}
	}

	// Absolute fallback: terminal bell
	os.Stdout.WriteString("\a")
}

// Stop stops any currently playing sound.
func (p *Player) Stop() {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.stop()
}

func (p *Player) stop() {
	if p.cmd != nil && p.cmd.Process != nil && p.playing {
		_ = p.cmd.Process.Kill()
		_ = p.cmd.Wait()
		p.playing = false
		p.cmd = nil
	}
}

func (p *Player) IsPlaying() bool {
	p.mu.Lock()
	defer p.mu.Unlock()
	return p.playing
}
