// Package agentlaunch persists the exact argv a runtime should execute.
package agentlaunch

import (
	"encoding/json"
	"fmt"
	"os"
)

// EnvSpecPath is the environment variable that holds the path to the launch spec file.
const EnvSpecPath = "AO_LAUNCH_SPEC"

// Spec describes the agent process the launcher trampoline should exec.
type Spec struct {
	WorkspacePath string   `json:"workspacePath"`
	Argv          []string `json:"argv"`
	FallbackArgv  []string `json:"fallbackArgv,omitempty"`
}

// WriteTemp serialises spec to a temporary JSON file and returns its path.
func WriteTemp(spec Spec) (string, error) {
	file, err := os.CreateTemp(os.TempDir(), "ao-launch-*.json")
	if err != nil {
		return "", fmt.Errorf("create launch spec: %w", err)
	}
	path := file.Name()
	enc := json.NewEncoder(file)
	enc.SetEscapeHTML(false)
	if err := enc.Encode(spec); err != nil {
		_ = file.Close()
		_ = os.Remove(path)
		return "", fmt.Errorf("write launch spec: %w", err)
	}
	if err := file.Close(); err != nil {
		_ = os.Remove(path)
		return "", fmt.Errorf("close launch spec: %w", err)
	}
	return path, nil
}

// ReadAndRemove reads and deletes the spec file at path, returning its contents.
func ReadAndRemove(path string) (Spec, error) {
	raw, err := os.ReadFile(path)
	if err != nil {
		return Spec{}, fmt.Errorf("read launch spec: %w", err)
	}
	_ = os.Remove(path)

	var spec Spec
	if err := json.Unmarshal(raw, &spec); err != nil {
		return Spec{}, fmt.Errorf("parse launch spec: %w", err)
	}
	if len(spec.Argv) == 0 {
		return Spec{}, fmt.Errorf("launch spec: argv is required")
	}
	return spec, nil
}
