package reportproxy

import (
	"context"
	"log/slog"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"time"
)

// EnsureLocalEngine checks if the NextReport engine is reachable at hostPort (default 127.0.0.1:5489).
// If unreachable and a local nextreport/server.mjs file exists, it starts the Node engine as a child process.
// It returns a cleanup function to terminate the child process upon server shutdown.
func EnsureLocalEngine(ctx context.Context, log *slog.Logger) func() {
	if log == nil {
		log = slog.Default()
	}

	// 1. Check if port 5489 is already responsive
	conn, err := net.DialTimeout("tcp", "127.0.0.1:5489", 500*time.Millisecond)
	if err == nil {
		_ = conn.Close()
		log.Info("NextReport engine is already running on 127.0.0.1:5489")
		return func() {}
	}

	// 2. Locate server.mjs
	candidates := []string{
		"nextreport/server.mjs",
		"./nextreport/server.mjs",
		"../nextreport/server.mjs",
		"../../keluargamart-nextreport/server.mjs",
	}

	var scriptPath string
	for _, c := range candidates {
		if abs, err := filepath.Abs(c); err == nil {
			if info, err := os.Stat(abs); err == nil && !info.IsDir() {
				scriptPath = abs
				break
			}
		}
	}

	if scriptPath == "" {
		log.Warn("nextreport/server.mjs not found; engine auto-start skipped (will rely on external NEXTREPORT_URL)")
		return func() {}
	}

	nodeBin, err := exec.LookPath("node")
	if err != nil {
		log.Warn("node binary not found in PATH; NextReport auto-start skipped")
		return func() {}
	}

	scriptDir := filepath.Dir(scriptPath)
	cmd := exec.Command(nodeBin, "server.mjs")
	cmd.Dir = scriptDir
	cmd.Env = append(os.Environ(), "PORT=5489", "HOST=127.0.0.1")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Start(); err != nil {
		log.Warn("Failed to start local NextReport engine", "error", err)
		return func() {}
	}

	log.Info("Starting embedded NextReport engine as child process", "pid", cmd.Process.Pid, "dir", scriptDir)

	// Wait up to 5s for the engine to accept connections
	started := false
	for i := 0; i < 25; i++ {
		time.Sleep(200 * time.Millisecond)
		c, err := net.DialTimeout("tcp", "127.0.0.1:5489", 200*time.Millisecond)
		if err == nil {
			_ = c.Close()
			started = true
			break
		}
	}

	if started {
		log.Info("Embedded NextReport engine is ready on http://127.0.0.1:5489")
	} else {
		log.Warn("Embedded NextReport engine started, but port 5489 not responsive yet")
	}

	return func() {
		if cmd.Process != nil {
			log.Info("Stopping embedded NextReport engine", "pid", cmd.Process.Pid)
			_ = cmd.Process.Kill()
			_ = cmd.Wait()
		}
	}
}
