package main

import (
	"path/filepath"
	"sort"
	"strings"
)

// ModuleGrouper groups Go source files into logical modules.
type ModuleGrouper struct {
	Prefixes map[string]string
}

// DefaultGrouper creates a grouper with default prefix rules for nats-server.
func DefaultGrouper() *ModuleGrouper {
	return &ModuleGrouper{
		Prefixes: map[string]string{
			"jetstream":          "jetstream",
			"consumer":           "jetstream",
			"stream":             "jetstream",
			"store":              "jetstream",
			"filestore":          "jetstream",
			"memstore":           "jetstream",
			"raft":               "raft",
			"gateway":            "gateway",
			"leafnode":           "leafnode",
			"route":              "route",
			"client":             "client",
			"client_proxyproto":  "client",
			"server":             "core",
			"service":            "core",
			"signal":             "core",
			"reload":             "core",
			"opts":               "config",
			"auth":               "auth",
			"auth_callout":       "auth",
			"jwt":                "auth",
			"nkey":               "auth",
			"accounts":           "accounts",
			"ocsp":               "tls",
			"ocsp_peer":          "tls",
			"ocsp_responsecache": "tls",
			"ciphersuites":       "tls",
			"parser":             "protocol",
			"proto":              "protocol",
			"sublist":            "subscriptions",
			"subject_transform":  "subscriptions",
			"monitor":            "monitoring",
			"monitor_sort_opts":  "monitoring",
			"mqtt":               "mqtt",
			"websocket":          "websocket",
			"events":             "events",
			"msgtrace":           "events",
			"log":                "logging",
			"errors":             "errors",
			"errors_gen":         "errors",
			"const":              "core",
			"util":               "core",
			"ring":               "core",
			"sendq":              "core",
			"ipqueue":            "core",
			"rate_counter":       "core",
			"scheduler":          "core",
			"sdm":                "core",
			"dirstore":           "core",
			"disk_avail":         "core",
			"elastic":            "core",
		},
	}
}

// GroupFiles takes a flat list of Go files and returns them grouped by module name.
func (g *ModuleGrouper) GroupFiles(files []string) map[string][]string {
	groups := make(map[string][]string)

	for _, f := range files {
		base := filepath.Base(f)
		base = strings.TrimSuffix(base, ".go")
		base = strings.TrimSuffix(base, "_test")

		for _, suffix := range []string{"_windows", "_linux", "_darwin", "_bsd",
			"_solaris", "_wasm", "_netbsd", "_openbsd", "_dragonfly", "_zos", "_other"} {
			base = strings.TrimSuffix(base, suffix)
		}

		module := g.classify(base)
		groups[module] = append(groups[module], f)
	}

	for k := range groups {
		sort.Strings(groups[k])
	}

	return groups
}

// classify determines which module a file belongs to based on its base name.
func (g *ModuleGrouper) classify(baseName string) string {
	if module, ok := g.Prefixes[baseName]; ok {
		return module
	}

	bestMatch := ""
	bestModule := "core"
	for prefix, module := range g.Prefixes {
		if strings.HasPrefix(baseName, prefix) && len(prefix) > len(bestMatch) {
			bestMatch = prefix
			bestModule = module
		}
	}

	return bestModule
}
