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
	
	defer func() {
		filesToCleanup := []string{r.TempFilePath}
		
		if r.Config.Run.Sourcemap {
			filesToCleanup = append(filesToCleanup, r.TempFilePath+".map")
		}
		
		for _, file := range filesToCleanup {
			if err := os.Remove(file); err != nil {
				if !os.IsNotExist(err) {
					// Silently ignore cleanup errors
				}
			}
		}
	}()

	if err := r.Builder.Build(opts); err != nil {
		fmt.Println("Build error:", err)
		return
	}
	
	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)
		return
	}

	var wg sync.WaitGroup
	wg.Add(1)

	go func() {
		defer wg.Done()
		cmd.Wait()
	}()

	wg.Wait()
}

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