package main

import (
	"bufio"
	"io/fs"
	"os"
	"path/filepath"
	"strings"

	"go.wit.com/log"
)

func doDrives() {
	parts, err := parseProcPartitions()
	if err != nil {
		panic(err)
	}

	for _, p := range parts {
		log.Printf("Device: /dev/%s\tSize: %d KiB\n", p.Name, p.Blocks)
	}

	blockDir := "/sys/block"
	mounts := getMountedDevices()

	log.Info("doDrives()", mounts)

	err = filepath.WalkDir(blockDir, func(path string, d fs.DirEntry, err error) error {
		if path == blockDir {
			return nil // skip root
		}
		if d.IsDir() && filepath.Dir(path) == blockDir {
			dev := d.Name()
			devPath := "/dev/" + dev
			log.Printf("Drive: %s\n", devPath)

			// Look for partitions
			partitions, err := filepath.Glob(filepath.Join(blockDir, dev, dev+"*"))
			if err != nil {
				return err
			}

			hasPartition := false
			used := false
			for _, part := range partitions {
				partName := filepath.Base(part)
				if partName == dev {
					continue // skip the main device
				}
				hasPartition = true
				partDev := "/dev/" + partName
				isMounted := mounts[partDev]
				log.Printf("  Partition: %s [%v]\n", partDev, isMounted)
				if isMounted {
					used = true
				}
			}

			if !hasPartition {
				log.Println("  No partitions found.")
			}

			if !used {
				log.Println("  → Drive appears to be unused.")
			}
		}
		return nil
	})

	if err != nil {
		panic(err)
	}
}

// getMountedDevices reads /proc/self/mountinfo and returns a map of mounted device paths
func getMountedDevices() map[string]bool {
	f, err := os.Open("/proc/self/mountinfo")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	mounted := make(map[string]bool)
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := scanner.Text()
		fields := strings.Fields(line)
		if len(fields) < 10 {
			continue
		}
		// Device path is after the last '-' token
		for i, field := range fields {
			if field == "-" && i+2 < len(fields) {
				dev := fields[i+2]
				if strings.HasPrefix(dev, "/dev/") {
					mounted[dev] = true
				}
				break
			}
		}
	}
	return mounted
}

type Partition struct {
	Major  int
	Minor  int
	Blocks int64
	Name   string
}

func parseProcPartitions() ([]Partition, error) {
	f, err := os.Open("/proc/partitions")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var partitions []Partition
	scanner := bufio.NewScanner(f)

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if strings.HasPrefix(line, "major") || line == "" {
			continue // Skip header and empty lines
		}

		var p Partition
		_, err := log.Sscanf(line, "%d %d %d %s", &p.Major, &p.Minor, &p.Blocks, &p.Name)
		if err != nil {
			return nil, log.Errorf("error parsing line: %q: %w", line, err)
		}
		partitions = append(partitions, p)
	}

	return partitions, scanner.Err()
}
