package collector

import (
	"os/exec"
	"strconv"
	"strings"
	"syscall"
)

type DiskInfo struct {
	Filesystem string `json:"filesystem"`
	TotalBytes int64  `json:"total_bytes"`
	UsedBytes  int64  `json:"used_bytes"`
	FreeBytes  int64  `json:"free_bytes"`
	MountPoint string `json:"mount_point"`
}

func CollectDisks() []DiskInfo {
	var disks []DiskInfo
	
	// df -T zur Anzeige aller mounted filesystems
	output, err := exec.Command("/usr/bin/df", "-T", "-P").CombinedOutput()
	if err != nil {
		return disks
	}
	
	lines := strings.Split(string(output), "\n")
	if len(lines) < 2 {
		return disks
	}
	
	// Erste Zeile ist Header, überspringen
	for _, line := range lines[1:] {
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}
		
		fields := strings.Fields(line)
		if len(fields) < 7 {
			continue
		}
		
		filesystem := fields[0]
		fstype := fields[1]
		totalKB := fields[2]
		usedKB := fields[3]
		availKB := fields[4]
		mountpoint := fields[6]
		
		// Überspringe spezielle Filesysteme
		if shouldSkipFilesystem(filesystem, fstype, mountpoint) {
			continue
		}
		
		// Konvertiere kB zu Bytes
		total, _ := strconv.ParseInt(totalKB, 10, 64)
		used, _ := strconv.ParseInt(usedKB, 10, 64)
		avail, _ := strconv.ParseInt(availKB, 10, 64)
		
		// Für bessere Genauigkeit: Versuche statvfs syscall
		if stat := getStatvfs(mountpoint); stat != nil {
			total = int64(stat.Blocks) * int64(stat.Bsize)
			avail = int64(stat.Bavail) * int64(stat.Bsize)
			used = total - avail
		} else {
			// Fallback: df-Werte in Bytes konvertieren
			total *= 1024
			used *= 1024
			avail *= 1024
		}
		
		disks = append(disks, DiskInfo{
			Filesystem: filesystem,
			TotalBytes: total,
			UsedBytes:  used,
			FreeBytes:  avail,
			MountPoint: mountpoint,
		})
	}
	
	return disks
}

// Bestimmt ob ein Filesystem übersprungen werden soll
func shouldSkipFilesystem(filesystem, fstype, mountpoint string) bool {
	// Überspringe virtuelle Filesysteme
	skipTypes := []string{
		"proc", "sysfs", "devfs", "devtmpfs", "tmpfs", "debugfs",
		"securityfs", "cgroup", "cgroup2", "pstore", "bpf",
		"tracefs", "configfs", "fusectl", "binfmt_misc",
		"autofs", "mqueue", "hugetlbfs", "sunrpc",
	}
	
	for _, skipType := range skipTypes {
		if fstype == skipType {
			return true
		}
	}
	
	// Überspringe spezielle Mount-Points
	skipMounts := []string{
		"/dev", "/proc", "/sys", "/run", "/tmp",
		"/dev/shm", "/run/lock", "/run/user",
	}
	
	for _, skipMount := range skipMounts {
		if strings.HasPrefix(mountpoint, skipMount) {
			return true
		}
	}
	
	// Überspringe Loop-Devices außer root
	if strings.HasPrefix(filesystem, "/dev/loop") && mountpoint != "/" {
		return true
	}
	
	// Überspringe Bind-Mounts (heuristic)
	if strings.Contains(mountpoint, "/snap/") {
		return true
	}
	
	return false
}

// Holt präzise Filesystem-Statistiken via statvfs syscall
func getStatvfs(path string) *syscall.Statfs_t {
	var stat syscall.Statfs_t
	if err := syscall.Statfs(path, &stat); err != nil {
		return nil
	}
	return &stat
}