package directory

import (
	"fmt"
	"os"
	"path/filepath"
	"rmm-hunter/internal/pkg/hunt/detect/common"
	. "rmm-hunter/internal/suspicious"
	"strings"
)

var appData = os.Getenv("APPDATA")

func Detect() []Directory {
	var suspiciousDirectories []Directory
	seen := make(map[string]bool) // Prevent duplicates

	fmt.Printf("[*] Enumerating Suspicious Directories \n")
	// Check for common directories
	for _, dir := range common.CommonDirectories {
		dir = replaceAppData(dir)

		// Check if this is a prefix pattern (ends with incomplete path such as Screen Connect "C:\Program Files (x86)\ScreenConnect Client (")
		if isPrefix(dir) {
			// Find all directories matching this prefix
			matches := findPrefixMatches(dir)
			for _, match := range matches {
				if !seen[match] {
					fmt.Printf("   [?] Found %s\n", match)
					suspiciousDirectories = append(suspiciousDirectories, Directory{Path: match})
					seen[match] = true
				}
			}
		} else {
			// Exact match
			if _, err := os.Stat(dir); err == nil {
				if !seen[dir] {
					fmt.Printf("   [?] Found %s\n", dir)
					suspiciousDirectories = append(suspiciousDirectories, Directory{Path: dir})
					seen[dir] = true
				}
			}
		}
	}
	fmt.Printf("[+] Found %d Suspicious Directories\n", len(suspiciousDirectories))

	return suspiciousDirectories
}

// replaceAppData replaces {{APPDATA}} with the actual APPDATA path
func replaceAppData(path string) string {
	if strings.Contains(path, "{{APPDATA}}") {
		p := strings.Replace(path, "{{APPDATA}}", "", -1)
		return filepath.Join(appData, p)
	}
	return path
}

// isPrefix checks if a path is a prefix pattern (incomplete path for matching)
func isPrefix(path string) bool {
	// If path ends with "(" or other incomplete patterns, it's a prefix
	return strings.HasSuffix(path, "(") || strings.HasSuffix(path, "\\")
}

// findPrefixMatches finds all directories that start with the given prefix
func findPrefixMatches(prefix string) []string {
	var matches []string

	// Get the parent directory to search in
	parentDir := filepath.Dir(prefix)

	// Check if parent directory exists
	if _, err := os.Stat(parentDir); os.IsNotExist(err) {
		return matches
	}

	// Read all entries in the parent directory
	entries, err := os.ReadDir(parentDir)
	if err != nil {
		return matches
	}

	// Get the base name prefix
	basePrefix := filepath.Base(prefix)

	// Check each entry
	for _, entry := range entries {
		if entry.IsDir() {
			// Check if this directory name starts with our prefix
			if strings.HasPrefix(entry.Name(), basePrefix) {
				fullPath := filepath.Join(parentDir, entry.Name())
				matches = append(matches, fullPath)
			}
		}
	}

	return matches
}
