// Convert-path adapter (design.md §3.7).
//
// Lead Convert emits one CONVERT event on the Lead plus one CREATE event for
// each created record (Account / Contact / Opportunity). All four events
// share the same TraceId so they correlate in AuditLog queries, and all
// carry Entrypoint=CONVERT with EntrypointDetail=<convertRequestId>.
//
// Pure builder — no DB writes. Wiring into the real Lead-convert path is a
// follow-up commit.

package audit

import (
	"errors"
	"fmt"
)

// ConvertAuthContext carries the actor + correlation ids shared across every
// event emitted by a single Lead Convert. The TraceId here is REQUIRED in
// spirit (the correlation guarantee depends on it); if the caller hasn't set
// one, the adapter does NOT synthesize one — that's a wiring bug worth
// surfacing. Validation still only demands what AuditEvent.Validate requires.
type ConvertAuthContext struct {
	ChangedById string
	RequestId   string
	TraceId     string
	SessionId   string
	ClientIp    string
	UserAgent   string
}

// ConvertedRecord is one record created by the Lead Convert process.
type ConvertedRecord struct {
	ObjectApiName string
	RecordId      string
}

// ConvertResult is the adapter-facing shape of a completed Lead Convert.
// CreatedOpportunity is optional (admin may disable it per LeadConvertSettings).
type ConvertResult struct {
	ConvertRequestId   string
	LeadId             string
	CreatedAccount     *ConvertedRecord
	CreatedContact     *ConvertedRecord
	CreatedOpportunity *ConvertedRecord
}

// ErrConvertInvalid signals a caller-contract violation that precedes
// AuditEvent.Validate (e.g. missing LeadId).
var ErrConvertInvalid = errors.New("audit: invalid ConvertResult")

// BuildConvertEvents emits (in order):
//   1. CONVERT on the Lead
//   2. CREATE on the Account (if present)
//   3. CREATE on the Contact (if present)
//   4. CREATE on the Opportunity (if present)
//
// Every event carries Entrypoint=CONVERT, EntrypointDetail=ConvertRequestId,
// and the shared TraceId from auth (for correlation across the four rows).
func BuildConvertEvents(auth ConvertAuthContext, result ConvertResult) ([]AuditEvent, error) {
	if auth.ChangedById == "" {
		return nil, fmt.Errorf("%w: ChangedById", ErrMissingRequired)
	}
	if result.LeadId == "" {
		return nil, fmt.Errorf("%w: LeadId", ErrConvertInvalid)
	}

	base := func(obj, rid string, action AuditAction) AuditEvent {
		return AuditEvent{
			ObjectApiName:    obj,
			RecordId:         rid,
			Action:           action,
			ChangedById:      auth.ChangedById,
			Entrypoint:       EntrypointConvert,
			EntrypointDetail: result.ConvertRequestId,
			Outcome:          OutcomeSuccess,
			RequestId:        auth.RequestId,
			TraceId:          auth.TraceId,
			SessionId:        auth.SessionId,
			ClientIp:         auth.ClientIp,
			UserAgent:        auth.UserAgent,
		}
	}

	events := []AuditEvent{base("Lead", result.LeadId, ActionConvert)}
	for _, cr := range []*ConvertedRecord{result.CreatedAccount, result.CreatedContact, result.CreatedOpportunity} {
		if cr == nil {
			continue
		}
		events = append(events, base(cr.ObjectApiName, cr.RecordId, ActionCreate))
	}

	for i := range events {
		if err := events[i].Validate(); err != nil {
			return nil, fmt.Errorf("event[%d]: %w", i, err)
		}
	}
	return events, nil
}
