package worker_test

import (
	"os"
	"path/filepath"
	"slices"
	"testing"

	"github.com/jfraeys/fetch_ml/internal/worker"
)

// TestScanExclusionsRecorded validates that scan exclusions are recorded in the manifest
func TestScanExclusionsRecorded(t *testing.T) {
	runDir := t.TempDir()

	mustWrite := func(rel string, data []byte) {
		p := filepath.Join(runDir, rel)
		if err := os.MkdirAll(filepath.Dir(p), 0750); err != nil {
			t.Fatalf("mkdir: %v", err)
		}
		if err := os.WriteFile(p, data, 0600); err != nil {
			t.Fatalf("write file: %v", err)
		}
	}

	mustWrite("run_manifest.json", []byte("{}"))
	mustWrite("output.log", []byte("log"))
	mustWrite("code/ignored.txt", []byte("ignore"))
	mustWrite("snapshot/ignored.bin", []byte("ignore"))

	mustWrite("results/metrics.jsonl", []byte("m"))
	mustWrite("checkpoints/best.pt", []byte("checkpoint"))
	mustWrite("plots/loss.png", []byte("png"))

	art, err := worker.ScanArtifacts(runDir, false, nil)
	if err != nil {
		t.Fatalf("scanArtifacts: %v", err)
	}
	if art == nil {
		t.Fatalf("expected artifacts")
	}

	paths := make([]string, 0, len(art.Files))
	var total int64
	for _, f := range art.Files {
		paths = append(paths, f.Path)
		total += f.SizeBytes
	}

	want := []string{
		"checkpoints/best.pt",
		"plots/loss.png",
		"results/metrics.jsonl",
	}
	if len(paths) != len(want) {
		t.Fatalf("expected %d files, got %d: %v", len(want), len(paths), paths)
	}
	for i := range want {
		if paths[i] != want[i] {
			t.Fatalf("expected paths[%d]=%q, got %q", i, want[i], paths[i])
		}
	}

	if art.TotalSizeBytes != total {
		t.Fatalf("expected total_size_bytes=%d, got %d", total, art.TotalSizeBytes)
	}
	if art.DiscoveryTime.IsZero() {
		t.Fatalf("expected discovery_time")
	}

	// R.5: Verify exclusions are recorded
	if len(art.Exclusions) == 0 {
		t.Fatal("expected exclusions to be recorded, got none")
	}

	// Build map of excluded paths to reasons
	exclusionMap := make(map[string]string)
	for _, ex := range art.Exclusions {
		exclusionMap[ex.Path] = ex.Reason
	}

	// Verify specific exclusions are recorded with correct reasons
	// Note: When directories are excluded with fs.SkipDir, files inside are not walked
	// so only the directory itself is recorded as excluded
	wantExclusions := map[string]string{
		"run_manifest.json": "manifest file excluded",
		"output.log":        "log files excluded",
		"code":              "source directory excluded",
		"snapshot":          "snapshot directory excluded",
	}

	for path, wantReason := range wantExclusions {
		reason, found := exclusionMap[path]
		if !found {
			t.Errorf("expected exclusion for %q not found", path)
			continue
		}
		if reason != wantReason {
			t.Errorf("exclusion reason for %q: got %q, want %q", path, reason, wantReason)
		}
	}

	// Verify no unexpected exclusions
	allowedExclusions := []string{
		"run_manifest.json",
		"output.log",
		"code",
		"snapshot",
	}
	for path := range exclusionMap {
		if !slices.Contains(allowedExclusions, path) {
			t.Errorf("unexpected exclusion: %q", path)
		}
	}
}
