package issuetrackerconformance

import (
	"go/parser"
	"go/token"
	"io/fs"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"testing"

	"github.com/nexuscrm/shared/pkg/contract"
)

const fixtureModule = "github.com/nexuscrm/app-packs-conformance/issue-tracker"

var _ PointReader = contract.Records(nil)

func TestFixturePinsPublishedManagedContract(t *testing.T) {
	data, err := os.ReadFile("go.mod")
	if err != nil {
		t.Fatal(err)
	}
	text := string(data)
	if !strings.Contains(text, "github.com/pingcap-inc/nexuscrm-contract v0.2.4") {
		t.Fatal("fixture does not pin published nexuscrm-contract v0.2.4")
	}
	if strings.Contains(text, "replace github.com/pingcap-inc/nexuscrm-contract") {
		t.Fatal("fixture substitutes the published nexuscrm-contract release")
	}
}

func TestFixtureDependencyClosureIsPublicAndAppNeutral(t *testing.T) {
	out, err := exec.Command("go", "list", "-deps", "-test", "-f", "{{if not .Standard}}{{.ImportPath}}{{end}}", "./...").CombinedOutput()
	if err != nil {
		t.Fatalf("go list dependency closure: %v\n%s", err, out)
	}
	allowed := []string{
		fixtureModule,
		"github.com/nexuscrm/shared",
		"github.com/pingcap-inc/nexuscrm-contract",
	}
	for _, dep := range strings.Split(string(out), "\n") {
		dep = strings.TrimSpace(dep)
		if dep == "" {
			continue
		}
		if !isAllowedFixtureDependency(dep, allowed) {
			t.Errorf("fixture dependency closure contains non-public or product dependency %q", dep)
		}
	}
}

func TestAllFixtureSourceImportsOnlyPublicNeutralPackages(t *testing.T) {
	allowedExternal := map[string]bool{
		"github.com/nexuscrm/shared/pkg/contract":                             true,
		"github.com/nexuscrm/shared/pkg/errors":                               true,
		"github.com/nexuscrm/shared/pkg/models":                               true,
		"github.com/pingcap-inc/nexuscrm-contract/pkg/controlplane":           true,
		"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/queryv1":        true,
		"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordaccessv1": true,
	}
	fset := token.NewFileSet()
	err := filepath.WalkDir(".", func(path string, entry fs.DirEntry, walkErr error) error {
		if walkErr != nil {
			return walkErr
		}
		if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
			return nil
		}
		file, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
		if err != nil {
			return err
		}
		for _, spec := range file.Imports {
			importPath, err := strconv.Unquote(spec.Path.Value)
			if err != nil {
				return err
			}
			if strings.Contains(importPath, ".") && !allowedExternal[importPath] {
				t.Errorf("%s imports non-public package %q", path, importPath)
			}
		}
		return nil
	})
	if err != nil {
		t.Fatalf("scan fixture Go sources: %v", err)
	}
}

func TestReleaseShapedIssueTrackerArtifactsAreAbsent(t *testing.T) {
	repoRoot := repositoryRoot(t)
	fixtureRoot, err := filepath.Abs(".")
	if err != nil {
		t.Fatalf("fixture root: %v", err)
	}
	for _, rel := range []string{
		"issue-tracker-standard",
		filepath.Join("dialects", "dialect-issue-tracker"),
	} {
		path := filepath.Join(repoRoot, rel)
		if _, err := os.Stat(path); err == nil {
			t.Errorf("release-shaped issue-tracker artifact returned: %s", path)
		} else if !os.IsNotExist(err) {
			t.Fatalf("stat %s: %v", path, err)
		}
	}

	forbiddenTokens := []string{"issue-tracker", "issuetracker"}
	productionArtifactNames := map[string]bool{
		"go.mod":               true,
		"pack.json":            true,
		"package.json":         true,
		"source-manifest.json": true,
		"source-index.json":    true,
		"Dockerfile":           true,
		"Makefile":             true,
	}
	err = filepath.WalkDir(repoRoot, func(path string, entry fs.DirEntry, walkErr error) error {
		if walkErr != nil {
			return walkErr
		}
		if entry.IsDir() {
			if path == fixtureRoot || entry.Name() == ".git" || entry.Name() == "node_modules" {
				return filepath.SkipDir
			}
			return nil
		}
		name := entry.Name()
		isProductionGo := strings.HasSuffix(name, ".go") && !strings.HasSuffix(name, "_test.go")
		isBuildOrReleaseControl := strings.HasSuffix(name, ".yml") || strings.HasSuffix(name, ".yaml") || strings.HasSuffix(name, ".sh")
		if !isProductionGo && !isBuildOrReleaseControl && !productionArtifactNames[name] {
			return nil
		}
		data, err := os.ReadFile(path)
		if err != nil {
			return err
		}
		for _, token := range forbiddenTokens {
			if strings.Contains(strings.ToLower(string(data)), token) {
				t.Errorf("release/build surface %s contains retired issue-tracker token %q", path, token)
			}
		}
		return nil
	})
	if err != nil {
		t.Fatalf("scan release/build surfaces: %v", err)
	}
}

func TestProductionSourcesDoNotDependOnFixture(t *testing.T) {
	repoRoot := repositoryRoot(t)
	fixtureRoot, err := filepath.Abs(".")
	if err != nil {
		t.Fatalf("fixture root: %v", err)
	}
	productionArtifactNames := map[string]bool{
		"go.mod":               true,
		"pack.json":            true,
		"package.json":         true,
		"source-manifest.json": true,
		"source-index.json":    true,
		"Dockerfile":           true,
		"Makefile":             true,
	}
	err = filepath.WalkDir(repoRoot, func(path string, entry fs.DirEntry, walkErr error) error {
		if walkErr != nil {
			return walkErr
		}
		if entry.IsDir() {
			if path == fixtureRoot || entry.Name() == ".git" || entry.Name() == "node_modules" {
				return filepath.SkipDir
			}
			return nil
		}
		name := entry.Name()
		isProductionGo := strings.HasSuffix(name, ".go") && !strings.HasSuffix(name, "_test.go")
		isBuildOrReleaseControl := strings.HasSuffix(name, ".yml") || strings.HasSuffix(name, ".yaml") || strings.HasSuffix(name, ".sh")
		if !isProductionGo && !isBuildOrReleaseControl && !productionArtifactNames[name] {
			return nil
		}
		data, err := os.ReadFile(path)
		if err != nil {
			return err
		}
		text := string(data)
		if strings.Contains(text, fixtureModule) || strings.Contains(text, "tests/conformance/issue-tracker") {
			t.Errorf("production source or manifest %s depends on the conformance fixture", path)
		}
		return nil
	})
	if err != nil {
		t.Fatalf("scan production sources: %v", err)
	}
}

func TestFixtureContainsNoProductionArtifactEntrypoint(t *testing.T) {
	forbiddenNames := map[string]bool{
		"main.go":              true,
		"pack.json":            true,
		"package.json":         true,
		"source-manifest.json": true,
		"Dockerfile":           true,
	}
	err := filepath.WalkDir(".", func(path string, entry fs.DirEntry, walkErr error) error {
		if walkErr != nil {
			return walkErr
		}
		if !entry.IsDir() && forbiddenNames[entry.Name()] {
			t.Errorf("fixture contains production artifact entrypoint %s", path)
		}
		if entry.IsDir() && entry.Name() == "cmd" {
			t.Errorf("fixture contains production command directory %s", path)
			return filepath.SkipDir
		}
		return nil
	})
	if err != nil {
		t.Fatalf("scan fixture artifacts: %v", err)
	}

	fset := token.NewFileSet()
	packages, err := parser.ParseDir(fset, ".", func(info fs.FileInfo) bool {
		return strings.HasSuffix(info.Name(), ".go") && !strings.HasSuffix(info.Name(), "_test.go")
	}, 0)
	if err != nil {
		t.Fatalf("parse fixture packages: %v", err)
	}
	for name := range packages {
		if name == "main" {
			t.Error("fixture declares package main")
		}
	}
}

func hasAllowedPrefix(value string, prefixes []string) bool {
	for _, prefix := range prefixes {
		if value == prefix || strings.HasPrefix(value, prefix+"/") {
			return true
		}
	}
	return false
}

func isAllowedFixtureDependency(value string, prefixes []string) bool {
	if strings.HasSuffix(value, ".test") {
		value = strings.TrimSuffix(value, ".test")
	}
	if strings.Contains(value, "[") {
		value = strings.TrimSpace(strings.SplitN(value, "[", 2)[0])
	}
	value = strings.TrimSuffix(value, "_test")
	return hasAllowedPrefix(value, prefixes)
}

func repositoryRoot(t *testing.T) string {
	t.Helper()
	wd, err := os.Getwd()
	if err != nil {
		t.Fatalf("get working directory: %v", err)
	}
	root := filepath.Clean(filepath.Join(wd, "..", "..", ".."))
	if _, err := os.Stat(filepath.Join(root, "AGENTS.md")); err != nil {
		t.Fatalf("resolve repository root %s: %v", root, err)
	}
	return root
}
