package speaker

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
)

type Server struct {
	Workdir string
	cmd     *exec.Cmd
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	mux := http.NewServeMux()
	mux.HandleFunc("POST /stop", s.stop)
	mux.HandleFunc("POST /play/ding", s.playDing)
	mux.HandleFunc("POST /play/alert", s.playAlert)
	mux.HandleFunc("POST /play/youtube", s.playYoutube)
	mux.HandleFunc("POST /play/soundcloud", s.playSoundcloud)
	mux.ServeHTTP(w, r)
}

func (s *Server) Stop() {
	if s.cmd != nil {
		s.cmd.Process.Kill()
		s.cmd.Process.Wait()
	}
}

func (s *Server) LoadSoundcloud(id string, stdout, stderr io.Writer) error {
	dir := filepath.Join(s.Workdir, "soundcloud")
	filename := fmt.Sprintf("%s.wav", id)
	_, err := os.Stat(filepath.Join(dir, filename))
	if err == nil {
		return err
	}
	if os.IsNotExist(err) {
		err = os.MkdirAll(dir, os.ModePerm)
		if err != nil {
			return err
		}
		cmd := exec.Command(
			"yt-dlp",
			"-f",
			"bestaudio",
			"--extract-audio",
			"--audio-format",
			"wav",
			"-o",
			filename,
			fmt.Sprintf("https://soundcloud.com/%s", id),
		)
		cmd.Dir = dir
		cmd.Stderr = stderr
		cmd.Stdout = stdout
		return cmd.Run()
	}
	return err
}

func (s *Server) LoadYoutube(id string, stdout, stderr io.Writer) error {
	dir := filepath.Join(s.Workdir, "youtube")
	filename := fmt.Sprintf("%s.wav", id)
	_, err := os.Stat(filepath.Join(dir, filename))
	if err == nil {
		return err
	}
	if os.IsNotExist(err) {
		err = os.MkdirAll(dir, os.ModePerm)
		if err != nil {
			return err
		}
		cmd := exec.Command(
			"yt-dlp",
			"-f",
			"bestaudio",
			"--extract-audio",
			"--audio-format",
			"wav",
			"-o",
			filename,
			fmt.Sprintf("https://www.youtube.com/watch?v=%s", id),
		)
		cmd.Dir = dir
		cmd.Stderr = stderr
		cmd.Stdout = stdout
		return cmd.Run()
	}
	return err
}

func (s *Server) Play(path string) error {
	s.Stop()
	path = filepath.Join(s.Workdir, path)
	s.cmd = exec.Command("aplay", path)
	return s.cmd.Start()
}

func (s *Server) stop(w http.ResponseWriter, r *http.Request) {
	s.Stop()
}

func (s *Server) playDing(w http.ResponseWriter, r *http.Request) {
	err := s.Play("ding.wav")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func (s *Server) playAlert(w http.ResponseWriter, r *http.Request) {
	err := s.Play("alert.wav")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
func (s *Server) playYoutube(w http.ResponseWriter, r *http.Request) {
	id := r.URL.Query().Get("id")
	err := s.LoadYoutube(id, w, w)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = s.Play(fmt.Sprintf("youtube/%s.wav", id))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func (s *Server) playSoundcloud(w http.ResponseWriter, r *http.Request) {
	id := r.URL.Query().Get("id")
	err := s.LoadSoundcloud(id, w, w)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = s.Play(fmt.Sprintf("soundcloud/%s.wav", id))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
