package records

import (
	"context"
	"strings"
	"time"

	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

// emitUpdateAuditsForRecordUpdate owns the PersistenceService update-path audit
// handoff: redact write-only update fields from the audit payload, emit the
// legacy/v2 bridge, and keep update-stage timing in one audit-owned place.
func (ps *PersistenceService) emitUpdateAuditsForRecordUpdate(txCtx context.Context, schema *models.ObjectMetadata, objectName, id string, effectiveUpdates, oldRecord models.SObject, currentUser *models.UserSession) error {
	auditUpdates := recordUpdateAuditPayload(objectName, effectiveUpdates)
	stageStart := time.Now()
	if err := ps.emitUpdateAudits(txCtx, schema, objectName, id, auditUpdates, oldRecord, currentUser); err != nil {
		logRecordStageTiming(txCtx, "Update", "complete.emitUpdateAudits", objectName, id, stageStart, err, len(auditUpdates))
		return err
	}
	logRecordStageTiming(txCtx, "Update", "complete.emitUpdateAudits", objectName, id, stageStart, nil, len(auditUpdates))
	return nil
}

// emitUpdateAudits is the single PersistenceService update-audit bridge. The
// v2 writer replaces legacy only in a graph with an explicitly injected
// durable producer; until then the legacy field-row writer remains the default
// compatibility path. The two
// writers must not both run for the same update because that double-populates
// _System_AuditLog once the v2 outbox worker expands field rows.
func (ps *PersistenceService) emitUpdateAudits(txCtx context.Context, schema *models.ObjectMetadata, objectName, id string, effectiveUpdates, oldRecord models.SObject, currentUser *models.UserSession) error {
	if ps.auditV2Emitter != nil {
		return ps.emitUpdateAuditV2(txCtx, schema, objectName, id, effectiveUpdates, oldRecord, currentUser)
	}
	return ps.generateAuditLogs(txCtx, schema, objectName, id, effectiveUpdates, oldRecord, currentUser)
}

func recordUpdateAuditPayload(objectName string, effectiveUpdates models.SObject) models.SObject {
	if !strings.EqualFold(objectName, constants.TableUser) {
		return effectiveUpdates
	}
	if _, hasPassword := effectiveUpdates[constants.FieldPassword]; !hasPassword {
		return effectiveUpdates
	}
	auditUpdates := make(models.SObject, len(effectiveUpdates))
	for k, v := range effectiveUpdates {
		if k != constants.FieldPassword {
			auditUpdates[k] = v
		}
	}
	return auditUpdates
}
