package connector_webhooks

import (
	"context"
	"strings"

	connectorcapabilities "github.com/pingcap-inc/nexuscrm-connectors/features/connector/capabilities"
	"golang.org/x/sync/singleflight"
)

// materializerParserSingleflight is an async receipt-router accelerator keyed by the
// connector pack incarnation. It only singleflights concurrent misses: every
// non-overlapping receipt still re-runs the registry's live capability gate.
type materializerParserSingleflightKey struct {
	namespace     string
	packInstallID string
}

type materializerParserSingleflight struct {
	group singleflight.Group
}

func newMaterializerParserSingleflight() *materializerParserSingleflight {
	return &materializerParserSingleflight{}
}

func (d *Dispatcher) resolveMaterializerParser(ctx context.Context, namespace, packInstallID string) (connectorcapabilities.EnvelopeParserHandler, error) {
	if d == nil || d.parserSingleflight == nil {
		return d.registry.ResolveEnvelopeParser(ctx, namespace, packInstallID)
	}
	return d.parserSingleflight.resolve(ctx, d.registry, namespace, packInstallID)
}

func (s *materializerParserSingleflight) resolve(ctx context.Context, registry *connectorcapabilities.Registry, namespace, packInstallID string) (connectorcapabilities.EnvelopeParserHandler, error) {
	if registry == nil {
		return nil, connectorcapabilities.ErrGateNotBound
	}
	key := normalizeMaterializerParserSingleflightKey(namespace, packInstallID)

	recordConnectorMaterializerParserSingleflight("miss")
	value, err, shared := s.group.Do(materializerParserSingleflightKeyString(key), func() (any, error) {
		recordConnectorMaterializerParserSingleflight("load")
		return registry.ResolveEnvelopeParser(ctx, namespace, packInstallID)
	})
	if shared {
		recordConnectorMaterializerParserSingleflight("shared")
	}
	if err != nil {
		recordConnectorMaterializerParserSingleflight("error")
		return nil, err
	}
	parser, ok := value.(connectorcapabilities.EnvelopeParserHandler)
	if !ok || parser == nil {
		recordConnectorMaterializerParserSingleflight("error")
		return nil, connectorcapabilities.ErrCapabilityNotAvailable
	}
	return parser, nil
}

func normalizeMaterializerParserSingleflightKey(namespace, packInstallID string) materializerParserSingleflightKey {
	return materializerParserSingleflightKey{
		namespace:     strings.ToLower(strings.TrimSpace(namespace)),
		packInstallID: strings.TrimSpace(packInstallID),
	}
}

func materializerParserSingleflightKeyString(key materializerParserSingleflightKey) string {
	return key.namespace + "\x00" + key.packInstallID
}
