package audit

import (
	"testing"
)

// TestBuildConvertEvents_HappyPath asserts the §3.7 convert fan-out:
// one CONVERT action on the Lead + one CREATE per created record
// (Account, Contact, Opportunity), all sharing the same TraceId and
// Entrypoint=CONVERT. EntrypointDetail carries the convert request id.
func TestBuildConvertEvents_HappyPath(t *testing.T) {
	t.Parallel()

	auth := ConvertAuthContext{
		ChangedById: "005xx0000000001",
		RequestId:   "req-convert-1",
		TraceId:     "trace-convert-shared",
	}
	result := ConvertResult{
		ConvertRequestId: "conv-42",
		LeadId:           "00Q000000000001",
		CreatedAccount:   &ConvertedRecord{ObjectApiName: "Account", RecordId: "001AAA"},
		CreatedContact:   &ConvertedRecord{ObjectApiName: "Contact", RecordId: "003CCC"},
		CreatedOpportunity: &ConvertedRecord{
			ObjectApiName: "Opportunity", RecordId: "006OOO",
		},
	}

	events, err := BuildConvertEvents(auth, result)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if got, want := len(events), 4; got != want {
		t.Fatalf("len(events) = %d, want %d (1 CONVERT + 3 CREATE)", got, want)
	}

	// Correlated TraceId across all four events.
	for i, ev := range events {
		if ev.TraceId != auth.TraceId {
			t.Errorf("event[%d].TraceId = %q, want shared %q", i, ev.TraceId, auth.TraceId)
		}
		if ev.Entrypoint != EntrypointConvert {
			t.Errorf("event[%d].Entrypoint = %q, want CONVERT", i, ev.Entrypoint)
		}
		if ev.EntrypointDetail != result.ConvertRequestId {
			t.Errorf("event[%d].EntrypointDetail = %q, want %q", i, ev.EntrypointDetail, result.ConvertRequestId)
		}
		if err := ev.Validate(); err != nil {
			t.Errorf("event[%d] Validate() failed: %v", i, err)
		}
	}

	// Shape: first event is CONVERT on Lead; next three are CREATE on the trio.
	if events[0].Action != ActionConvert || events[0].ObjectApiName != "Lead" || events[0].RecordId != result.LeadId {
		t.Errorf("event[0] = %+v; want CONVERT on Lead %s", events[0], result.LeadId)
	}
	wantCreates := map[string]string{"Account": "001AAA", "Contact": "003CCC", "Opportunity": "006OOO"}
	for _, ev := range events[1:] {
		if ev.Action != ActionCreate {
			t.Errorf("follow-up event action = %q, want CREATE", ev.Action)
		}
		if wantCreates[ev.ObjectApiName] != ev.RecordId {
			t.Errorf("unexpected CREATE event %s/%s", ev.ObjectApiName, ev.RecordId)
		}
	}
}

// TestBuildConvertEvents_OptionalOpportunity omits Opportunity (admin disabled).
func TestBuildConvertEvents_OptionalOpportunity(t *testing.T) {
	t.Parallel()

	auth := ConvertAuthContext{ChangedById: "005", TraceId: "tr"}
	result := ConvertResult{
		ConvertRequestId: "c1",
		LeadId:           "00Q1",
		CreatedAccount:   &ConvertedRecord{ObjectApiName: "Account", RecordId: "001A"},
		CreatedContact:   &ConvertedRecord{ObjectApiName: "Contact", RecordId: "003C"},
	}
	events, err := BuildConvertEvents(auth, result)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if got := len(events); got != 3 {
		t.Fatalf("len(events) = %d, want 3 (CONVERT + Account + Contact)", got)
	}
}

// TestBuildConvertEvents_InvalidInput rejects missing LeadId / ChangedById.
func TestBuildConvertEvents_InvalidInput(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name string
		auth ConvertAuthContext
		r    ConvertResult
	}{
		{"missing LeadId", ConvertAuthContext{ChangedById: "005"}, ConvertResult{ConvertRequestId: "c1"}},
		{"missing ChangedById", ConvertAuthContext{}, ConvertResult{ConvertRequestId: "c1", LeadId: "00Q"}},
	}
	for _, tc := range cases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()
			if _, err := BuildConvertEvents(tc.auth, tc.r); err == nil {
				t.Fatal("expected error, got nil")
			}
		})
	}
}
