package plugins

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

func TestInstallerInstallsAndTogglesPlugin(t *testing.T) {
	root := t.TempDir()
	pkg := buildTestQPlug(t, Manifest{
		SchemaVersion: 1,
		ID:            "pay-demo",
		Name:          "Pay Demo",
		Version:       "1.2.3",
		Runtime:       RuntimeJSONRPC,
		Entry:         map[string]string{"default": "bin/pay-demo"},
		Capabilities:  []string{CapabilityPayment},
	})
	service := NewService([]string{root}, 0, nil)
	result, err := service.Install(context.Background(), bytes.NewReader(pkg), InstallOptions{Filename: "pay-demo.qplug", Enable: true})
	if err != nil {
		t.Fatalf("Install() error = %v", err)
	}
	if result.Manifest.ID != "pay-demo" || !result.Manifest.Enabled {
		t.Fatalf("unexpected manifest: %#v", result.Manifest)
	}
	if _, err := os.Stat(filepath.Join(root, "pay-demo", "1.2.3", "plugin.json")); err != nil {
		t.Fatalf("installed plugin.json missing: %v", err)
	}

	if _, err := service.SetEnabled(context.Background(), "pay-demo", "1.2.3", false); err != nil {
		t.Fatalf("SetEnabled(false) error = %v", err)
	}
	if err := service.Call(context.Background(), "pay-demo", CapabilityPayment, MethodPaymentCreate, nil, nil); err == nil {
		t.Fatal("disabled plugin should not resolve for calls")
	}
	items, err := service.ListAll(context.Background(), CapabilityPayment)
	if err != nil {
		t.Fatalf("ListAll() error = %v", err)
	}
	if len(items) != 1 || items[0].Enabled {
		t.Fatalf("disabled plugin not visible in admin list: %#v", items)
	}
}

func buildTestQPlug(t *testing.T, manifest Manifest) []byte {
	t.Helper()
	var buf bytes.Buffer
	writer := zip.NewWriter(&buf)
	raw, _ := json.Marshal(manifest)
	addZipFile(t, writer, "plugin.json", raw)
	addZipFile(t, writer, "bin/pay-demo", []byte("#!/bin/sh\n"))
	if err := writer.Close(); err != nil {
		t.Fatal(err)
	}
	return buf.Bytes()
}

func addZipFile(t *testing.T, writer *zip.Writer, name string, data []byte) {
	t.Helper()
	file, err := writer.Create(name)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := file.Write(data); err != nil {
		t.Fatal(err)
	}
}
