package plan

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

	"metis/pkg/image"
	"metis/pkg/inventory"
	"metis/pkg/mount"
	"metis/pkg/writer"
)

// Execute performs a burn if confirm is true. With confirm=false, it only downloads/verifies and returns the plan.
func Execute(inv *inventory.Inventory, nodeName, device, cacheDir string, confirm bool) (*Plan, error) {
	p, err := Build(inv, nodeName, device, cacheDir)
	if err != nil {
		return nil, err
	}
	cacheImage := filepath.Join(cacheDir, cacheName(p.Image))
	cacheImage, err = image.DownloadAndVerify(p.Image, cacheImage, checksumFromInventory(inv, nodeName))
	if err != nil {
		return p, fmt.Errorf("download image: %w", err)
	}
	if !confirm {
		return p, nil
	}
	if device == "" || device == "/dev/sdX" {
		return p, fmt.Errorf("refusing to write to placeholder device")
	}
	ctx := context.Background()
	if err := writer.WriteImage(ctx, cacheImage, device); err != nil {
		return p, fmt.Errorf("write image: %w", err)
	}
	if err := maybeInject(inv, nodeName); err != nil {
		return p, fmt.Errorf("inject config: %w", err)
	}
	if auto := maybeAutoMount(device); auto != nil {
		defer mount.Teardown(auto)
		if err := maybeInject(inv, nodeName); err != nil {
			return p, fmt.Errorf("inject (auto-mount): %w", err)
		}
	}
	return p, nil
}

func checksumFromInventory(inv *inventory.Inventory, node string) string {
	_, cls, err := inv.FindNode(node)
	if err != nil || cls == nil {
		return ""
	}
	return cls.Checksum
}

func maybeAutoMount(device string) *mount.LoopMount {
	if os.Getenv("METIS_AUTO_MOUNT") == "" {
		return nil
	}
	// Use mount helper against the written device partitions.
	m, err := mount.Setup(device)
	if err != nil {
		return nil
	}
	// Propagate mount paths for injection.
	if m.BootPath != "" {
		_ = os.Setenv("METIS_BOOT_PATH", m.BootPath)
	}
	if m.RootPath != "" {
		_ = os.Setenv("METIS_ROOT_PATH", m.RootPath)
	}
	return m
}
