package fsfilters

import "strings"

var readOnlyFilesystemPatterns = []struct {
	reason     string
	substrings []string
}{
	{reason: "erofs", substrings: []string{"erofs"}},
	{reason: "squashfs", substrings: []string{"squashfs", "squash-fs"}},
	{reason: "iso9660", substrings: []string{"iso9660"}},
	{reason: "cdfs", substrings: []string{"cdfs"}},
	{reason: "udf", substrings: []string{"udf"}},
	{reason: "cramfs", substrings: []string{"cramfs"}},
	{reason: "romfs", substrings: []string{"romfs"}},
}

// ReadOnlyFilesystemReason returns a label explaining why a filesystem should be
// ignored for usage calculations, along with a boolean indicating whether it is
// a read-only filesystem that always reports full usage. This helps us avoid
// false positives from immutable root images (overlay/squashfs/erofs) that ship
// with Home Assistant OS and similar appliances, as well as snap mounts on Ubuntu
// systems (see issues #505, #690).
func ReadOnlyFilesystemReason(fsType string, totalBytes, usedBytes uint64) (string, bool) {
	ft := strings.ToLower(strings.TrimSpace(fsType))
	if ft == "" {
		return "", false
	}

	// Common read-only filesystem types used for immutable system partitions.
	for _, pattern := range readOnlyFilesystemPatterns {
		for _, needle := range pattern.substrings {
			if strings.Contains(ft, needle) {
				return pattern.reason, true
			}
		}
	}

	// Overlay-style filesystems can report 100% usage even though writes are
	// redirected elsewhere. Treat them as read-only when the reported usage is
	// saturated so we fall back to the writable layer metrics instead.
	if strings.Contains(ft, "overlay") || strings.Contains(ft, "overlayfs") {
		if totalBytes > 0 && usedBytes >= totalBytes {
			return "overlay", true
		}
	}

	return "", false
}

// ShouldIgnoreReadOnlyFilesystem reports whether the filesystem should be
// skipped from usage aggregation.
func ShouldIgnoreReadOnlyFilesystem(fsType string, totalBytes, usedBytes uint64) bool {
	_, skip := ReadOnlyFilesystemReason(fsType, totalBytes, usedBytes)
	return skip
}

// virtualFSTypes are filesystem types that represent virtual/pseudo filesystems
// which should not be counted toward disk usage.
var virtualFSTypes = map[string]bool{
	"tmpfs":      true,
	"devtmpfs":   true,
	"cgroup":     true,
	"cgroup2":    true,
	"sysfs":      true,
	"proc":       true,
	"devpts":     true,
	"securityfs": true,
	"debugfs":    true,
	"tracefs":    true,
	"fusectl":    true,
	"configfs":   true,
	"pstore":     true,
	"hugetlbfs":  true,
	"mqueue":     true,
	"bpf":        true,
}

// networkFSPatterns are substrings that indicate network/remote filesystems.
var networkFSPatterns = []string{"fuse", "9p", "nfs", "cifs", "smb"}

// specialMountPrefixes are mountpoint prefixes that indicate system mounts.
var specialMountPrefixes = []string{
	"/dev",
	"/proc",
	"/sys",
	"/run",
	"/var/lib/docker",
	"/snap",
}

// ShouldSkipFilesystem determines if a filesystem should be excluded from disk
// usage aggregation. It checks for read-only filesystems, virtual/pseudo filesystems,
// network mounts, and special system mountpoints. Returns skip=true if the filesystem
// should be excluded, along with a list of reason strings.
func ShouldSkipFilesystem(fsType, mountpoint string, totalBytes, usedBytes uint64) (skip bool, reasons []string) {
	fsTypeLower := strings.ToLower(strings.TrimSpace(fsType))

	// Check read-only filesystems (existing logic)
	if reason, isReadOnly := ReadOnlyFilesystemReason(fsType, totalBytes, usedBytes); isReadOnly {
		reasons = append(reasons, "read-only-"+reason)
	}

	// Check virtual filesystem types
	if virtualFSTypes[fsTypeLower] {
		reasons = append(reasons, "special-fs-type")
	}

	// Check network filesystem patterns
	for _, pattern := range networkFSPatterns {
		if strings.Contains(fsTypeLower, pattern) {
			reasons = append(reasons, "special-fs-type")
			break
		}
	}

	// Check special mountpoint prefixes
	for _, prefix := range specialMountPrefixes {
		if strings.HasPrefix(mountpoint, prefix) {
			reasons = append(reasons, "special-mountpoint")
			break
		}
	}

	// Check specific special mountpoints
	if mountpoint == "/boot/efi" {
		reasons = append(reasons, "special-mountpoint")
	}

	// Windows System Reserved partition
	if mountpoint == "System Reserved" || strings.Contains(mountpoint, "System Reserved") {
		reasons = append(reasons, "special-mountpoint")
	}

	return len(reasons) > 0, reasons
}
