package persistence

import (
	"context"
	"strings"
	"sync/atomic"
	"time"

	"github.com/nexuscrm/kernel/pkg/perftiming"
)

type transactionTimingIDKey struct{}

var transactionTimingSequence atomic.Uint64

// WithPerfTiming returns a context with performance timing instrumentation enabled.
// Timing logs are only emitted when this flag is present on the context.
func WithPerfTiming(ctx context.Context) context.Context {
	return perftiming.WithEnabled(ctx)
}

func withTransactionTimingID(ctx context.Context) context.Context {
	if !perftiming.Enabled(ctx) {
		return ctx
	}
	return context.WithValue(ctx, transactionTimingIDKey{}, transactionTimingSequence.Add(1))
}

func logRepositorySQLTiming(ctx context.Context, operation, table, readSource, sqlText string, paramsCount, fields, rows int, started time.Time, err error) {
	if !perftiming.Enabled(ctx) {
		return
	}
	perftiming.Event(ctx, "repo_sql_timing", started, err).
		Str("operation", operation).
		Str("table", table).
		Str("read_source", readSource).
		Int("params_count", paramsCount).
		Int("fields", fields).
		Int("rows", rows).
		Str("sql", trimTimingSQL(sqlText)).
		Msg("Repository SQL timing")
}

func logTransactionStageTiming(ctx context.Context, operation, stage string, started time.Time, err error) {
	if !perftiming.Enabled(ctx) {
		return
	}
	event := perftiming.Event(ctx, "transaction_stage_timing", started, err).
		Str("operation", operation).
		Str("stage", stage)
	if transactionID, _ := ctx.Value(transactionTimingIDKey{}).(uint64); transactionID != 0 {
		event = event.Uint64("transaction_id", transactionID)
	}
	event.Msg("Transaction stage timing")
}

func logOutboxRepositoryStageTiming(ctx context.Context, stage string, eventType string, fields int, started time.Time, err error) {
	if !perftiming.Enabled(ctx) {
		return
	}
	perftiming.Event(ctx, "outbox_repository_timing", started, err).
		Str("stage", stage).
		Str("event_type", eventType).
		Int("fields", fields).
		Msg("Outbox repository timing")
}

func trimTimingSQL(sqlText string) string {
	sqlText = strings.Join(strings.Fields(sqlText), " ")
	if len(sqlText) <= 2000 {
		return sqlText
	}
	return sqlText[:2000] + "...<truncated>"
}
