//go:build windows

package procscan

import (
	"strings"
	"syscall"
	"unsafe"

	"golang.org/x/sys/windows"
)

// Snapshot returns a map of PID → exe basename for every running
// process whose exe name (case-insensitively) matches one of the
// names in `targets`. Pass an empty/nil targets to capture all
// processes (useful for debugging).
func Snapshot(targets []string) (map[uint32]string, error) {
	snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
	if err != nil {
		return nil, err
	}
	defer windows.CloseHandle(snap)

	var entry windows.ProcessEntry32
	entry.Size = uint32(unsafe.Sizeof(entry))

	if err := windows.Process32First(snap, &entry); err != nil {
		return nil, err
	}

	wantAll := len(targets) == 0
	wantSet := make(map[string]struct{}, len(targets))
	for _, n := range targets {
		wantSet[strings.ToLower(n)] = struct{}{}
	}

	out := map[uint32]string{}
	for {
		exeName := syscall.UTF16ToString(entry.ExeFile[:])
		if wantAll {
			out[entry.ProcessID] = exeName
		} else if _, ok := wantSet[strings.ToLower(exeName)]; ok {
			out[entry.ProcessID] = exeName
		}
		err := windows.Process32Next(snap, &entry)
		if err != nil {
			if err == syscall.ERROR_NO_MORE_FILES {
				break
			}
			return nil, err
		}
	}
	return out, nil
}

// DiffPIDs reports which PIDs are added (in cur but not prev) and
// removed (in prev but not cur). Used by the engine's procscan ticker
// to decide whether to rebuild the WinDivert filter.
func DiffPIDs(prev, cur map[uint32]string) (added, removed []uint32) {
	for pid := range cur {
		if _, ok := prev[pid]; !ok {
			added = append(added, pid)
		}
	}
	for pid := range prev {
		if _, ok := cur[pid]; !ok {
			removed = append(removed, pid)
		}
	}
	return
}
