package overlay

import (
	"context"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"sub2api-cn-relay-manager/internal/pack"
)

func TestApplyCopiesSourceAndAppliesPatch(t *testing.T) {
	sourceDir := t.TempDir()
	if err := os.MkdirAll(filepath.Join(sourceDir, "backend"), 0o755); err != nil {
		t.Fatalf("MkdirAll() error = %v", err)
	}
	if err := os.WriteFile(filepath.Join(sourceDir, "backend", "hello.txt"), []byte("hello\n"), 0o644); err != nil {
		t.Fatalf("WriteFile() error = %v", err)
	}

	packDir := t.TempDir()
	patchBody := strings.Join([]string{
		"diff --git a/backend/hello.txt b/backend/hello.txt",
		"--- a/backend/hello.txt",
		"+++ b/backend/hello.txt",
		"@@ -1 +1 @@",
		"-hello",
		"+patched",
		"",
	}, "\n")
	patchPath := filepath.Join(packDir, "overlays", "sample.patch")
	if err := os.MkdirAll(filepath.Dir(patchPath), 0o755); err != nil {
		t.Fatalf("MkdirAll() error = %v", err)
	}
	if err := os.WriteFile(patchPath, []byte(patchBody), 0o644); err != nil {
		t.Fatalf("WriteFile() error = %v", err)
	}

	result, err := Apply(context.Background(), ApplyRequest{
		PackDir:   packDir,
		SourceDir: sourceDir,
		Overlays: []pack.HostOverlay{{
			OverlayID: "sample",
			PatchPath: "overlays/sample.patch",
		}},
	})
	if err != nil {
		t.Fatalf("Apply() error = %v", err)
	}
	body, err := os.ReadFile(filepath.Join(result.OutputDir, "backend", "hello.txt"))
	if err != nil {
		t.Fatalf("ReadFile() error = %v", err)
	}
	if string(body) != "patched\n" {
		t.Fatalf("patched file = %q, want %q", string(body), "patched\n")
	}
	if _, err := os.Stat(result.MetadataFilePath); err != nil {
		t.Fatalf("Stat(metadata) error = %v", err)
	}
}

func TestApplySupportsRelativePackDir(t *testing.T) {
	workspaceDir := t.TempDir()
	originalWD, err := os.Getwd()
	if err != nil {
		t.Fatalf("Getwd() error = %v", err)
	}
	if err := os.Chdir(workspaceDir); err != nil {
		t.Fatalf("Chdir() error = %v", err)
	}
	t.Cleanup(func() {
		_ = os.Chdir(originalWD)
	})

	sourceDir := filepath.Join(workspaceDir, "source")
	if err := os.MkdirAll(filepath.Join(sourceDir, "backend"), 0o755); err != nil {
		t.Fatalf("MkdirAll() error = %v", err)
	}
	if err := os.WriteFile(filepath.Join(sourceDir, "backend", "hello.txt"), []byte("hello\n"), 0o644); err != nil {
		t.Fatalf("WriteFile() error = %v", err)
	}

	packDir := filepath.Join(workspaceDir, "pack")
	patchPath := filepath.Join(packDir, "overlays", "sample.patch")
	if err := os.MkdirAll(filepath.Dir(patchPath), 0o755); err != nil {
		t.Fatalf("MkdirAll() error = %v", err)
	}
	patchBody := strings.Join([]string{
		"diff --git a/backend/hello.txt b/backend/hello.txt",
		"--- a/backend/hello.txt",
		"+++ b/backend/hello.txt",
		"@@ -1 +1 @@",
		"-hello",
		"+patched",
		"",
	}, "\n")
	if err := os.WriteFile(patchPath, []byte(patchBody), 0o644); err != nil {
		t.Fatalf("WriteFile() error = %v", err)
	}

	result, err := Apply(context.Background(), ApplyRequest{
		PackDir:   "pack",
		SourceDir: sourceDir,
		Overlays: []pack.HostOverlay{{
			OverlayID: "sample",
			PatchPath: "overlays/sample.patch",
		}},
	})
	if err != nil {
		t.Fatalf("Apply() with relative pack dir error = %v", err)
	}
	body, err := os.ReadFile(filepath.Join(result.OutputDir, "backend", "hello.txt"))
	if err != nil {
		t.Fatalf("ReadFile() error = %v", err)
	}
	if string(body) != "patched\n" {
		t.Fatalf("patched file = %q, want %q", string(body), "patched\n")
	}
}

func TestFilterOverlaysRejectsMissingOverlayID(t *testing.T) {
	_, err := FilterOverlays([]pack.HostOverlay{{OverlayID: "sample"}}, "missing")
	if err == nil || !strings.Contains(err.Error(), `overlay "missing" did not match`) {
		t.Fatalf("FilterOverlays() error = %v, want missing overlay detail", err)
	}
}
