package util

import (
	"fmt"
	"syscall"
)

// DiskUsage represents available/total disk space in bytes.
type DiskUsage struct {
	FreeBytes  uint64
	TotalBytes uint64
}

// CheckDisk returns free and total disk space for the given path.
func CheckDisk(path string) (*DiskUsage, error) {
	var stat syscall.Statfs_t

	err := syscall.Statfs(path, &stat)
	if err != nil {
		return nil, fmt.Errorf("statfs: %w", err)
	}

	free := stat.Bavail * uint64(stat.Bsize)
	total := stat.Blocks * uint64(stat.Bsize)

	return &DiskUsage{
		FreeBytes:  free,
		TotalBytes: total,
	}, nil
}

// HasEnoughSpace returns true if "path" has at least requiredMB available.
func HasEnoughSpace(path string, requiredMB uint64) (bool, *DiskUsage, error) {
	usage, err := CheckDisk(path)
	if err != nil {
		return false, nil, err
	}

	requiredBytes := requiredMB * 1024 * 1024
	return usage.FreeBytes >= requiredBytes, usage, nil
}

// RequireSpace errors if insufficient disk is available.
func RequireSpace(path string, minMB uint64) error {
	ok, usage, err := HasEnoughSpace(path, minMB)
	if err != nil {
		return err
	}
	if !ok {
		return fmt.Errorf(
			"insufficient disk: free=%dMB required=%dMB",
			usage.FreeBytes/1024/1024,
			minMB,
		)
	}
	return nil
}
