package models_test

// Architecture test (#2344): models is a leaf — it carries pure type
// definitions and must not import any other internal/* package. Almost
// every package in workspace-server depends on models; if models grew a
// reverse dep, the import graph would cycle.
//
// If this test fails: you put behavior inside models. Move the behavior
// to whichever package actually owns it (handlers, provisioner, db, …)
// and have *that* package import models, not the reverse.

import (
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

const moduleInternalPrefix = "github.com/Molecule-AI/molecule-monorepo/platform/internal/"

func TestModelsHasNoInternalDependencies(t *testing.T) {
	t.Parallel()
	for path, file := range listImports(t, ".") {
		if strings.HasPrefix(path, moduleInternalPrefix) {
			t.Errorf(
				"models must not import other internal packages "+
					"(found %q in %s) — models is the pure-types leaf and any "+
					"reverse dep creates an import cycle since most packages "+
					"depend on models. See workspace-server/internal/models/architecture_test.go.",
				path, file,
			)
		}
	}
}

func listImports(t *testing.T, dir string) map[string]string {
	t.Helper()
	fset := token.NewFileSet()
	entries, err := os.ReadDir(dir)
	if err != nil {
		t.Fatalf("read %s: %v", dir, err)
	}
	out := make(map[string]string)
	for _, e := range entries {
		name := e.Name()
		if e.IsDir() || !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
			continue
		}
		f, err := parser.ParseFile(fset, filepath.Join(dir, name), nil, parser.ImportsOnly)
		if err != nil {
			t.Fatalf("parse %s: %v", name, err)
		}
		for _, imp := range f.Imports {
			path := strings.Trim(imp.Path.Value, "\"")
			if _, seen := out[path]; !seen {
				out[path] = name
			}
		}
	}
	return out
}
