package agentd

import (
	"testing"

	agentv1 "github.com/wangjia/pangolin/server/internal/pb/agentv1"
)

func TestHandleCommandIdempotentAndOrdered(t *testing.T) {
	a := New(testConfig(t), WithRestarter(&fakeRestarter{}))
	a.sb.ApplyConfig(sampleSnapshot(), true) // inbounds present

	upsert := func(id int64, dp string) *agentv1.Command {
		return &agentv1.Command{
			CommandID: id,
			Type:      agentv1.CommandTypeUpsert,
			Upsert:    &agentv1.UpsertPayload{Credential: &agentv1.Credential{DpUUID: dp, Protocol: agentv1.ProtocolBoth}},
		}
	}

	// Apply id=1, then redelivered id=1 (dropped Ack) — applied once, no regression.
	a.handleCommand(upsert(1, "alpha"))
	a.handleCommand(upsert(1, "alpha"))
	if a.lastCommandID.Load() != 1 {
		t.Fatalf("lastCommandID = %d, want 1", a.lastCommandID.Load())
	}

	// A stale command at or below the high-water mark must be skipped (idempotent
	// at-least-once redelivery): revoke at id=1 should NOT remove alpha.
	a.handleCommand(&agentv1.Command{
		CommandID: 1,
		Type:      agentv1.CommandTypeRevoke,
		Revoke:    &agentv1.RevokePayload{DpUUID: "alpha"},
	})
	if !a.sb.Has("alpha") {
		t.Error("revoke with stale id=1 should have been skipped, but alpha was removed")
	}

	// Forward progress: id=2 revokes alpha.
	a.handleCommand(&agentv1.Command{
		CommandID: 2,
		Type:      agentv1.CommandTypeRevoke,
		Revoke:    &agentv1.RevokePayload{DpUUID: "alpha"},
	})
	if a.sb.Has("alpha") {
		t.Error("alpha should be revoked by id=2")
	}
	if a.lastCommandID.Load() != 2 {
		t.Fatalf("lastCommandID = %d, want 2", a.lastCommandID.Load())
	}
}

func TestHandleApplyConfigUpdatesInbounds(t *testing.T) {
	a := New(testConfig(t), WithRestarter(&fakeRestarter{}))
	a.handleCommand(&agentv1.Command{
		CommandID:   1,
		Type:        agentv1.CommandTypeApplyConfig,
		ApplyConfig: sampleSnapshot(&agentv1.Credential{DpUUID: "z", Protocol: agentv1.ProtocolReality}),
	})
	if a.sb.ConfigVersion() != 7 {
		t.Errorf("config version = %d, want 7", a.sb.ConfigVersion())
	}
	if !a.sb.Has("z") {
		t.Error("apply_config credential z not applied")
	}
}
