package supervise

import (
	"context"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/pocketbase/pocketbase"
	"github.com/pocketbase/pocketbase/core"
	"github.com/pocketbase/pocketbase/tools/router"
)

func ServeSubprocessSupervisor(app *pocketbase.PocketBase, se *core.ServeEvent) *router.Route[*core.RequestEvent] {

	command, _ := app.RootCmd.PersistentFlags().GetString("subcommand")

	if len(command) > 0 {
		cmdsub := strings.Split(command, " ")
		if len(cmdsub) > 0 {
			startNodeProcessSupervised(cmdsub[0], strings.Join(cmdsub[1:], " "))
		}
	}
	return nil
}

func startNodeProcessSupervised(command string, args ...string) {
	const maxRetries = 3
	const retryDelay = 30 * time.Second

	var (
		cmdMu sync.Mutex
		cmd   *exec.Cmd
	)

	stopChan := make(chan os.Signal, 1)
	signal.Notify(stopChan, os.Interrupt, syscall.SIGTERM)

	go func() {
		retries := 0

		for {
			select {
			case <-stopChan:
				log.Println("Received shutdown signal. Terminating subprocess...")
				cmdMu.Lock()
				if cmd != nil && cmd.Process != nil {
					_ = cmd.Process.Signal(syscall.SIGTERM)
				}
				cmdMu.Unlock()
				return

			default:
				ctx, cancel := context.WithCancel(context.Background())
				cmdMu.Lock()
				cmd = exec.CommandContext(ctx, command, args...)
				cmd.Stdout = os.Stdout
				cmd.Stderr = os.Stderr
				cmdMu.Unlock()

				log.Printf("Starting Process: %s %v\n", command, args)
				err := cmd.Run()
				cancel() // cancel the context when done

				if err != nil {
					log.Printf("Process exited with error: %v\n", err)
					retries++
					if retries >= maxRetries {
						log.Printf("Process failed %d times. Shutting down application...", retries)
						// _ = app.ResetBootstrapState()
						os.Exit(1)
					}
					log.Printf("Retrying in %s (%d/%d)...", retryDelay, retries, maxRetries)
					time.Sleep(retryDelay)
				} else {
					log.Printf("Process exited normally. Resetting retry count.")
					retries = 0
				}
			}
		}
	}()

}
