package main

import (
	"os"
	"path/filepath"
	"strings"

	"go.wit.com/log"
)

type DevInfo struct {
	Name   string
	IsRaw  bool
	Type   string
	Parent string // raw device if this entry is a partition
}

func doDrives2() {
	parts, err := parseProcPartitions()
	if err != nil {
		log.Printf("Error reading /proc/partitions: %v\n", err)
		os.Exit(1)
	}

	// Determine raw devices and type
	devs := make(map[string]*DevInfo)
	for _, p := range parts {
		devs[p.Name] = &DevInfo{Name: p.Name}
	}

	for _, info := range devs {
		sysPath := filepath.Join("/sys/block", info.Name)
		if exists(sysPath) {
			info.IsRaw = true
			typ := detectType(sysPath)
			info.Type = typ
		} else {
			info.IsRaw = false
			info.Parent = findParent(info.Name, devs)
		}
	}

	for _, info := range devs {
		devPath := "/dev/" + info.Name
		if info.IsRaw {
			s := log.Sprintf("%-12s -> %-8s (raw)", devPath, info.Type)
			log.Info(s)
			me.dd.AddText(s)
		} else {
			if info.Parent != "" {
				log.Printf("%-12s -> partition of /dev/%s\n", devPath, info.Parent)
			} else {
				log.Printf("%-12s -> unknown (no parent found)\n", devPath)
			}
		}
	}
}

/*
// parseProcPartitions parses /proc/partitions entries
func parseProcPartitions() ([]struct {
	Name string
}, error) {
	f, err := os.Open("/proc/partitions")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	scanner := bufio.NewScanner(f)
	var parts []struct{ Name string }
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, "major") {
			continue
		}
		fields := strings.Fields(line)
		if len(fields) < 4 {
			continue
		}
		parts = append(parts, struct{ Name string }{Name: fields[3]})
	}
	return parts, scanner.Err()
}
*/

// exists checks if the given path exists
func exists(path string) bool {
	_, err := os.Lstat(path)
	return err == nil
}

// detectType determines device type by resolving sysPath and inspecting parent directories
func detectType(sysPath string) string {
	resolved, err := filepath.EvalSymlinks(sysPath)
	if err != nil {
		return "unknown"
	}
	resolved = filepath.ToSlash(resolved)

	switch {
	case strings.Contains(resolved, "/nvme"):
		return "NVMe"
	case strings.Contains(resolved, "/mmc_host") || strings.Contains(resolved, "/mmc"):
		return "MMC/SD"
	case strings.Contains(resolved, "/usb"):
		return "USB"
	case strings.Contains(resolved, "/loop"):
		return "Loop"
	case strings.Contains(resolved, "/ram"):
		return "RAM disk"
	default:
		return "SCSI/SATA"
	}
}

// findParent identifies the raw device for a partition, based on name heuristics
func findParent(name string, devs map[string]*DevInfo) string {
	for candidate := range devs {
		if candidate == name {
			continue
		}
		if strings.HasPrefix(name, candidate) {
			return candidate
		}
	}
	return ""
}
