package autonumber

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type previewCounterStateContextKey struct{}

type previewCounterState struct {
	mu   sync.Mutex
	next map[previewCounterKey]int64
}

type previewCounterKey struct {
	fieldID  string
	scopeKey string
}

// WithPreviewCounterState attaches preview-local counter state to ctx. No-DML
// flow previews call PreviewOne once per captured create, so this state gives a
// single preview run the same contiguous counter progression live inserts get
// from DB reservations while still leaving _System_AutoNumberCounter untouched.
func WithPreviewCounterState(ctx context.Context) context.Context {
	if ctx == nil {
		ctx = context.Background()
	}
	if previewCounterStateFromContext(ctx) != nil {
		return ctx
	}
	return context.WithValue(ctx, previewCounterStateContextKey{}, &previewCounterState{
		next: map[previewCounterKey]int64{},
	})
}

func previewCounterStateFromContext(ctx context.Context) *previewCounterState {
	if ctx == nil {
		return nil
	}
	state, _ := ctx.Value(previewCounterStateContextKey{}).(*previewCounterState)
	return state
}

func nextPreviewCounterValue(ctx context.Context, in reserveInput, assignedAt time.Time, currentNext int64) (int64, error) {
	state := previewCounterStateFromContext(ctx)
	if state == nil {
		return currentNext, nil
	}
	scopeKey, err := scopeKeyFor(in, assignedAt)
	if err != nil {
		return 0, fmt.Errorf("autonumber preview: scope_key: %w", err)
	}
	key := previewCounterKey{fieldID: in.fieldID, scopeKey: scopeKey}

	state.mu.Lock()
	defer state.mu.Unlock()
	if next, ok := state.next[key]; ok {
		state.next[key] = next + 1
		return next, nil
	}
	state.next[key] = currentNext + 1
	return currentNext, nil
}
