package infra

import (
	"encoding/csv"
	"errors"
	"fmt"
	"os/exec"
	"strconv"
	"strings"
)

// GetGpuInfo queries NVIDIA GPUs via nvidia-smi and returns a slice of GpuInfo.
// If nvidia-smi is not installed or no NVIDIA GPU is present, returns an empty
// slice and a nil error (absence of NVIDIA hardware is not an error).
func GetGpuInfo() ([]GpuInfo, error) {
	out, err := exec.Command(
		"nvidia-smi",
		"--query-gpu=index,name,memory.total,memory.free,driver_version,cuda_version",
		"--format=csv,noheader,nounits",
	).Output()

	if err != nil {
		// nvidia-smi not installed or no NVIDIA device — not an error.
		var exitErr *exec.ExitError
		if errors.Is(err, exec.ErrNotFound) || errors.As(err, &exitErr) {
			return []GpuInfo{}, nil
		}
		return nil, fmt.Errorf("gpu_info: nvidia-smi: %w", err)
	}

	r := csv.NewReader(strings.NewReader(strings.TrimSpace(string(out))))
	r.TrimLeadingSpace = true

	records, err := r.ReadAll()
	if err != nil {
		return nil, fmt.Errorf("gpu_info: parse csv: %w", err)
	}

	gpus := make([]GpuInfo, 0, len(records))
	for _, rec := range records {
		if len(rec) < 6 {
			continue
		}

		idx, _ := strconv.Atoi(strings.TrimSpace(rec[0]))
		totalMb, _ := strconv.Atoi(strings.TrimSpace(rec[2]))
		freeMb, _ := strconv.Atoi(strings.TrimSpace(rec[3]))

		gpus = append(gpus, GpuInfo{
			Index:         idx,
			Name:          strings.TrimSpace(rec[1]),
			VramTotalMb:   totalMb,
			VramFreeMb:    freeMb,
			DriverVersion: strings.TrimSpace(rec[4]),
			CudaVersion:   strings.TrimSpace(rec[5]),
		})
	}

	return gpus, nil
}
