package proxmox

import (
	"context"
	"net/http"
	"testing"
)

// TestRouting_APIOpsNeverShellOut asserts the API path never invokes the
// privileged runner: API ops (read + mutating) go only through the HTTP doer.
func TestRouting_APIOpsNeverShellOut(t *testing.T) {
	runner := &mockRunner{}
	// If any API op tried to use a runner, it would have to be wired here — it
	// cannot be, because Client has no runner field. We still assert structurally:
	// run a batch of API ops with a recording doer and confirm the runner is idle.
	d := &mockDoer{fn: func(r *http.Request) (*http.Response, error) {
		// Generic OK responses sufficient for the calls below.
		if r.Method == http.MethodGet {
			return jsonResp(200, `{"data":[]}`), nil
		}
		return jsonResp(200, `{"data":"`+testUPID+`"}`), nil
	}}
	c := newTestClient(d)
	ctx := context.Background()

	_, _ = c.Version(ctx)
	_, _ = c.Nodes(ctx)
	_, _ = c.ListLXC(ctx)
	_, _ = c.NodeStorage(ctx)
	_, _ = c.Snapshot(ctx, 9001, "s1", "")
	_, _ = c.Rollback(ctx, 9001, "s1")
	_, _ = c.Vzdump(ctx, VzdumpOptions{VMID: 9001, Storage: "local", Mode: ModeStop})
	_, _ = c.RestoreLXC(ctx, RestoreLXCOptions{VMID: 9100, Archive: "local:backup/a.tar.zst", Storage: "local-lvm"})
	_, _ = c.Start(ctx, 9001)
	_, _ = c.Stop(ctx, 9001)

	if runner.calls != 0 {
		t.Fatalf("API ops invoked the privileged runner %d time(s) — fence broken", runner.calls)
	}
	if d.calls == 0 {
		t.Fatalf("expected API ops to use the HTTP doer")
	}
}

// TestRouting_PrivilegedOpsNeverHTTP asserts the fenced root path never makes an
// HTTP call: Privileged ops go only through the runner.
func TestRouting_PrivilegedOpsNeverHTTP(t *testing.T) {
	d := &mockDoer{fn: func(r *http.Request) (*http.Response, error) {
		t.Fatalf("privileged op made an HTTP call to %s — fence broken", r.URL)
		return nil, nil
	}}
	_ = d // a Privileged has no doer field; this doer is unreachable by construction.

	runner := &mockRunner{out: []byte(`{"ok":true}`)}
	p := NewPrivileged(runner, "demo-felhom")
	ctx := context.Background()

	if err := p.CreateGoldenLXC(ctx, GoldenLXCSpec{VMID: 9999, OSTemplate: "local:vztmpl/x.tar.zst", Storage: "local-lvm"}); err != nil {
		t.Fatalf("CreateGoldenLXC: %v", err)
	}
	if err := p.MountUSBByUUID(ctx, "1234-ABCD", "/mnt/usb"); err != nil {
		t.Fatalf("MountUSBByUUID: %v", err)
	}
	if _, err := p.SMART(ctx, "/dev/sda"); err != nil {
		t.Fatalf("SMART: %v", err)
	}
	if _, err := p.Sensors(ctx); err != nil {
		t.Fatalf("Sensors: %v", err)
	}
	if runner.calls == 0 {
		t.Fatalf("expected privileged ops to use the runner")
	}
}

// TestPrivileged_CreateGoldenForcesKeyctl asserts the golden create always carries
// the keyctl feature flag (the whole reason it is root-fenced).
func TestPrivileged_CreateGoldenForcesKeyctl(t *testing.T) {
	runner := &mockRunner{}
	p := NewPrivileged(runner, "demo-felhom")
	if err := p.CreateGoldenLXC(context.Background(), GoldenLXCSpec{
		VMID: 9999, OSTemplate: "local:vztmpl/x.tar.zst", Storage: "local-lvm", RootFSGB: 8,
	}); err != nil {
		t.Fatalf("CreateGoldenLXC: %v", err)
	}
	if runner.lastCmd != "pct" {
		t.Errorf("cmd = %q, want pct", runner.lastCmd)
	}
	var sawFeatures bool
	for i, a := range runner.lastArg {
		if a == "--features" && i+1 < len(runner.lastArg) && runner.lastArg[i+1] == "nesting=1,keyctl=1" {
			sawFeatures = true
		}
	}
	if !sawFeatures {
		t.Errorf("pct create args missing keyctl features: %v", runner.lastArg)
	}
}
