package plan

import (
	"fmt"
	"os"
	"path/filepath"
	"time"

	"metis/pkg/inventory"
)

// Action describes a step in the burn process.
type Action struct {
	Type    string `json:"type"`
	Detail  string `json:"detail"`
	Command string `json:"command,omitempty"`
}

// Plan describes the overall burn for a node.
type Plan struct {
	Node    string   `json:"node"`
	Device  string   `json:"device"`
	Image   string   `json:"image"`
	Class   string   `json:"class"`
	Actions []Action `json:"actions"`
}

// Build constructs a plan without executing it.
func Build(inv *inventory.Inventory, nodeName, device, cacheDir string) (*Plan, error) {
	node, class, err := inv.FindNode(nodeName)
	if err != nil {
		return nil, err
	}
	if device == "" {
		device = "/dev/sdX" // placeholder
	}
	cacheImage := filepath.Join(cacheDir, filepath.Base(class.Image))
	actions := []Action{
		{Type: "fetch", Detail: fmt.Sprintf("Download %s to %s", class.Image, cacheImage)},
	}
	if class.Checksum != "" {
		actions = append(actions, Action{Type: "verify", Detail: fmt.Sprintf("Verify checksum %s", class.Checksum)})
	}
	actions = append(actions, Action{Type: "write", Detail: fmt.Sprintf("Write image to %s", device), Command: fmt.Sprintf("dd if=%s of=%s bs=4M status=progress conv=fsync", cacheImage, device)})
	if boot := os.Getenv("METIS_BOOT_PATH"); boot != "" {
		actions = append(actions, Action{Type: "inject", Detail: fmt.Sprintf("Inject config into boot mount %s", boot)})
	}
	if root := os.Getenv("METIS_ROOT_PATH"); root != "" {
		actions = append(actions, Action{Type: "inject", Detail: fmt.Sprintf("Inject config into root mount %s", root)})
	}
	if os.Getenv("METIS_BOOT_PATH") == "" && os.Getenv("METIS_ROOT_PATH") == "" {
		actions = append(actions, Action{Type: "inject", Detail: "Inject hostname/network/k3s config (requires mounted boot/root; skipped if unset)"})
	}
	actions = append(actions, Action{Type: "finalize", Detail: fmt.Sprintf("Ready to insert SD for %s", node.Hostname)})

	return &Plan{
		Node:    nodeName,
		Device:  device,
		Image:   class.Image,
		Class:   class.Name,
		Actions: actions,
	}, nil
}

// NextRunStale returns true if the last success was older than the given duration.
func NextRunStale(lastSuccess time.Time, maxAge time.Duration) bool {
	return time.Since(lastSuccess) > maxAge
}
