package platform

import (
	"archive/zip"
	"encoding/json"
	"os"
	"path/filepath"
	"testing"

	"github.com/Eriyc/rules_wails/pkg/wails3kit/updates"
)

func TestExtractBundleRejectsTraversal(t *testing.T) {
	t.Parallel()

	archivePath := filepath.Join(t.TempDir(), "bundle.zip")
	file, err := os.Create(archivePath)
	if err != nil {
		t.Fatalf("Create returned error: %v", err)
	}
	writer := zip.NewWriter(file)
	entry, err := writer.Create("../escape")
	if err != nil {
		t.Fatalf("Create entry returned error: %v", err)
	}
	if _, err := entry.Write([]byte("bad")); err != nil {
		t.Fatalf("Write returned error: %v", err)
	}
	if err := writer.Close(); err != nil {
		t.Fatalf("Close writer returned error: %v", err)
	}
	if err := file.Close(); err != nil {
		t.Fatalf("Close file returned error: %v", err)
	}

	if _, _, err := extractBundle(t.Context(), archivePath, updates.ArtifactFormatZip); err == nil {
		t.Fatal("expected traversal archive to fail")
	}
}

func TestApplyBundleReplacesFilesAndPreservesArgs(t *testing.T) {
	t.Parallel()

	root := t.TempDir()
	stage := t.TempDir()
	if err := os.MkdirAll(filepath.Join(root, "resources"), 0o755); err != nil {
		t.Fatalf("MkdirAll returned error: %v", err)
	}
	if err := os.WriteFile(filepath.Join(root, "App"), []byte("old"), 0o755); err != nil {
		t.Fatalf("WriteFile returned error: %v", err)
	}
	if err := os.WriteFile(filepath.Join(root, "resources", "config.json"), []byte("old"), 0o644); err != nil {
		t.Fatalf("WriteFile returned error: %v", err)
	}
	if err := os.MkdirAll(filepath.Join(stage, "resources"), 0o755); err != nil {
		t.Fatalf("MkdirAll returned error: %v", err)
	}
	if err := os.WriteFile(filepath.Join(stage, "App"), []byte("new"), 0o755); err != nil {
		t.Fatalf("WriteFile returned error: %v", err)
	}
	if err := os.WriteFile(filepath.Join(stage, "resources", "config.json"), []byte("new"), 0o644); err != nil {
		t.Fatalf("WriteFile returned error: %v", err)
	}

	request := helperRequest{
		InstallRoot: root,
		StagedPath:  stage,
		Bundle: updates.BundleManifest{
			SchemaVersion: 1,
			EntryPoint:    "App",
			Files: []updates.BundleFile{
				{Path: "App", Mode: "0755"},
				{Path: "resources/config.json", Mode: "0644"},
			},
		},
	}

	if err := applyBundle(request); err != nil {
		t.Fatalf("applyBundle returned error: %v", err)
	}

	bytes, err := os.ReadFile(filepath.Join(root, "App"))
	if err != nil {
		t.Fatalf("ReadFile returned error: %v", err)
	}
	if string(bytes) != "new" {
		t.Fatalf("unexpected executable contents: %s", string(bytes))
	}
	bytes, err = os.ReadFile(filepath.Join(root, "resources", "config.json"))
	if err != nil {
		t.Fatalf("ReadFile returned error: %v", err)
	}
	if string(bytes) != "new" {
		t.Fatalf("unexpected resource contents: %s", string(bytes))
	}
}

func TestMaybeRunIgnoresNormalArgs(t *testing.T) {
	t.Parallel()

	handled, err := MaybeRun([]string{"app"})
	if err != nil {
		t.Fatalf("MaybeRun returned error: %v", err)
	}
	if handled {
		t.Fatal("expected MaybeRun to ignore non-helper args")
	}
}

func TestHelperRequestJSONRoundTrip(t *testing.T) {
	t.Parallel()

	request := helperRequest{
		InstallRoot: "/tmp/app",
		StagedPath:  "/tmp/stage",
		Bundle: updates.BundleManifest{
			SchemaVersion: 1,
			EntryPoint:    "App",
			Files:         []updates.BundleFile{{Path: "App", Mode: "0755"}},
		},
		Args: []string{"--flag"},
	}
	bytes, err := json.Marshal(request)
	if err != nil {
		t.Fatalf("Marshal returned error: %v", err)
	}
	var decoded helperRequest
	if err := json.Unmarshal(bytes, &decoded); err != nil {
		t.Fatalf("Unmarshal returned error: %v", err)
	}
	if decoded.Bundle.EntryPoint != "App" {
		t.Fatalf("unexpected entrypoint: %s", decoded.Bundle.EntryPoint)
	}
}
