package esr

import (
	"esr/internal/config"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"syscall"
	"time"
)

type Runner struct {
	Config       *config.Config
	EntryPoint   string
	Builder      *Builder
	TempFilePath string
}

func NewRunner(c *config.Config, b *Builder, e string) *Runner {
	return &Runner{
		Config:       c,
		EntryPoint:   e,
		Builder:      b,
		TempFilePath: newTempFilePath(e),
	}
}

func newTempFilePath(entry string) string {
	timestamp := time.Now().UnixNano()
	// tempDir := os.TempDir()
	// return filepath.Join(tempDir, fmt.Sprintf("esr-%d.mjs", timestamp))
	return filepath.Join(
		filepath.Dir(entry),
		fmt.Sprintf("esr-%d.mjs", timestamp),
	)
}

func (r *Runner) Run(entryPoint string) {
	opts := ModeOptions(r.Config, ModeRunner, entryPoint, r.TempFilePath)
	opts.Outfile = r.TempFilePath

	if err := r.Builder.Build(opts); err != nil {
		fmt.Println("Build error:", err)
		return
	}

	fmt.Printf("esr :: running: \"%s %s\"\n", r.Config.Run.Runtime, r.TempFilePath)

	cmd := exec.Command(r.Config.Run.Runtime, r.TempFilePath)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	if err := cmd.Start(); err != nil {
		fmt.Println("Error starting process:", err)
		os.Exit(1)
	}

	var wg sync.WaitGroup
	wg.Add(1)

	go func() {
		defer wg.Done()
		if err := cmd.Wait(); err != nil {
			fmt.Printf("Process finished with error: %v\n", err)
		} else {
			fmt.Println("Process finished successfully")
		}
	}()

	wg.Wait()

	// Finally, remove the temp file we created

	if err := os.Remove(r.TempFilePath); err != nil {
		fmt.Printf("Failed to remove temp file: %v\n", err)
	}
}

func (r *Runner) Stop(cmd *exec.Cmd) error {
	if cmd.Process != nil {
		return cmd.Process.Signal(syscall.SIGINT)
	}
	return nil
}
