func WithInvitationDID(didID string) ConnectionOption {
	return func(c *Connection) {
		c.InvitationDID = didID
	}
}
WithInvitationDID sets InvitationDID on the connection record.
package didexchange
import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/google/uuid"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/didexchange"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/mediator"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/transport"
	"github.com/hyperledger/aries-framework-go/pkg/doc/did"
	"github.com/hyperledger/aries-framework-go/pkg/doc/util/kmsdidkey"
	"github.com/hyperledger/aries-framework-go/pkg/kms"
	"github.com/hyperledger/aries-framework-go/pkg/store/connection"
	"github.com/hyperledger/aries-framework-go/pkg/vdr/fingerprint"
	"github.com/hyperledger/aries-framework-go/spi/storage"
)
const (
	InvitationMsgType = didexchange.InvitationMsgType
	RequestMsgType = didexchange.RequestMsgType
	ProtocolName = didexchange.DIDExchange
)
var ErrConnectionNotFound = errors.New("connection not found")
type options struct {
	routerConnections  []string
	routerConnectionID string
}
func applyOptions(args ...Opt) *options {
	opts := &options{}
	for i := range args {
		args[i](opts)
	}
	return opts
}
type Opt func(*options)
type InvOpt Opt
func WithRouterConnectionID(conn string) InvOpt {
	return func(opts *options) {
		opts.routerConnectionID = conn
	}
}
func WithRouterConnections(conns ...string) Opt {
	return func(opts *options) {
		for _, conn := range conns {
			if conn != "" {
				opts.routerConnections = append(opts.routerConnections, conn)
			}
		}
	}
}
type provider interface {
	Service(id string) (interface{}, error)
	KMS() kms.KeyManager
	ServiceEndpoint() string
	StorageProvider() storage.Provider
	ProtocolStateStorageProvider() storage.Provider
	KeyType() kms.KeyType
	KeyAgreementType() kms.KeyType
	MediaTypeProfiles() []string
}
type Client struct {
	service.Event
	didexchangeSvc    protocolService
	routeSvc          mediator.ProtocolService
	kms               kms.KeyManager
	serviceEndpoint   string
	connectionStore   *connection.Recorder
	keyType           kms.KeyType
	keyAgreementType  kms.KeyType
	mediaTypeProfiles []string
}
type protocolService interface {
	service.DIDComm
	AcceptExchangeRequest(connectionID, publicDID, label string, routerConnections []string) error
	AcceptInvitation(connectionID, publicDID, label string, routerConnections []string) error
	CreateImplicitInvitation(inviterLabel, inviterDID, inviteeLabel,
		inviteeDID string, routerConnections []string) (string, error)
	CreateConnection(*connection.Record, *did.Doc) error
}
func New(ctx provider) (*Client, error) {
	svc, err := ctx.Service(didexchange.DIDExchange)
	if err != nil {
		return nil, err
	}
	didexchangeSvc, ok := svc.(protocolService)
	if !ok {
		return nil, errors.New("cast service to DIDExchange Service failed")
	}
	s, err := ctx.Service(mediator.Coordination)
	if err != nil {
		return nil, err
	}
	routeSvc, ok := s.(mediator.ProtocolService)
	if !ok {
		return nil, errors.New("cast service to Route Service failed")
	}
	connectionStore, err := connection.NewRecorder(ctx)
	if err != nil {
		return nil, err
	}
	keyType := ctx.KeyType()
	if keyType == "" {
		keyType = kms.ED25519Type
	}
	keyAgreementType := ctx.KeyAgreementType()
	if keyAgreementType == "" {
		keyAgreementType = kms.X25519ECDHKWType
	}
	mtp := ctx.MediaTypeProfiles()
	if len(mtp) == 0 {
		mtp = []string{transport.MediaTypeRFC0019EncryptedEnvelope}
	}
	return &Client{
		Event:             didexchangeSvc,
		didexchangeSvc:    didexchangeSvc,
		routeSvc:          routeSvc,
		kms:               ctx.KMS(),
		serviceEndpoint:   ctx.ServiceEndpoint(),
		connectionStore:   connectionStore,
		keyType:           keyType,
		keyAgreementType:  keyAgreementType,
		mediaTypeProfiles: mtp,
	}, nil
}
func (c *Client) CreateInvitation(label string, args ...InvOpt) (*Invitation, error) {
	opts := &options{}
	for i := range args {
		args[i](opts)
	}
	keyType := c.keyType
	for _, mediaType := range c.mediaTypeProfiles {
		if mediaType == transport.MediaTypeDIDCommV2Profile || mediaType == transport.MediaTypeAIP2RFC0587Profile {
			keyType = c.keyAgreementType
			break
		}
	}
	_, pubKey, err := c.kms.CreateAndExportPubKeyBytes(keyType)
	if err != nil {
		return nil, fmt.Errorf("createInvitation: failed to extract public SigningKey bytes from handle: %w", err)
	}
	var didKey string
	switch keyType {
	case kms.ED25519Type:
		didKey, _ = fingerprint.CreateDIDKey(pubKey)
	default:
		didKey, err = kmsdidkey.BuildDIDKeyByKeyType(pubKey, keyType)
		if err != nil {
			return nil, fmt.Errorf("createInvitation: failed to build did:key by key type: %w", err)
		}
	}
	var (
		serviceEndpoint = c.serviceEndpoint
		routingKeys     []string
	)
	if opts.routerConnectionID != "" {
		serviceEndpoint, routingKeys, err = mediator.GetRouterConfig(c.routeSvc,
			opts.routerConnectionID, c.serviceEndpoint)
		if err != nil {
			return nil, fmt.Errorf("createInvitation: getRouterConfig: %w", err)
		}
		if err = mediator.AddKeyToRouter(c.routeSvc, opts.routerConnectionID, didKey); err != nil {
			return nil, fmt.Errorf("createInvitation: AddKeyToRouter: %w", err)
		}
	}
	invitation := &didexchange.Invitation{
		ID:              uuid.New().String(),
		Label:           label,
		RecipientKeys:   []string{didKey},
		ServiceEndpoint: serviceEndpoint,
		Type:            didexchange.InvitationMsgType,
		RoutingKeys:     routingKeys,
	}
	err = c.connectionStore.SaveInvitation(invitation.ID, invitation)
	if err != nil {
		return nil, fmt.Errorf("createInvitation: failed to save invitation: %w", err)
	}
	return &Invitation{invitation}, nil
}
func (c *Client) CreateInvitationWithDID(label, publicDID string) (*Invitation, error) {
	invitation := &didexchange.Invitation{
		ID:    uuid.New().String(),
		Label: label,
		DID:   publicDID,
		Type:  didexchange.InvitationMsgType,
	}
	err := c.connectionStore.SaveInvitation(invitation.ID, invitation)
	if err != nil {
		return nil, fmt.Errorf("createInvitationWithDID: failed to save invitation with DID: %w", err)
	}
	return &Invitation{invitation}, nil
}
func (c *Client) HandleInvitation(invitation *Invitation) (string, error) {
	payload, err := json.Marshal(invitation)
	if err != nil {
		return "", fmt.Errorf("handleInvitation: failed marshal invitation: %w", err)
	}
	msg, err := service.ParseDIDCommMsgMap(payload)
	if err != nil {
		return "", fmt.Errorf("handleInvitation: failed to create DIDCommMsg: %w", err)
	}
	connectionID, err := c.didexchangeSvc.HandleInbound(msg, service.EmptyDIDCommContext())
	if err != nil {
		return "", fmt.Errorf("handleInvitation: failed from didexchange service handle: %w", err)
	}
	return connectionID, nil
}
func (c *Client) AcceptInvitation(connectionID, publicDID, label string, args ...Opt) error {
	opts := applyOptions(args...)
	if err := c.didexchangeSvc.AcceptInvitation(connectionID, publicDID, label, opts.routerConnections); err != nil {
		return fmt.Errorf("did exchange client - accept exchange invitation: %w", err)
	}
	return nil
}
func (c *Client) AcceptExchangeRequest(connectionID, publicDID, label string, args ...Opt) error {
	err := c.didexchangeSvc.AcceptExchangeRequest(connectionID, publicDID, label,
		applyOptions(args...).routerConnections)
	if err != nil {
		return fmt.Errorf("did exchange client - accept exchange request: %w", err)
	}
	return nil
}
func (c *Client) CreateImplicitInvitation(inviterLabel, inviterDID string, args ...Opt) (string, error) {
	return c.didexchangeSvc.CreateImplicitInvitation(inviterLabel, inviterDID,
		"", "", applyOptions(args...).routerConnections)
}
func (c *Client) CreateImplicitInvitationWithDID(inviter, invitee *DIDInfo) (string, error) {
	if inviter == nil || invitee == nil {
		return "", errors.New("missing inviter and/or invitee public DID(s)")
	}
	return c.didexchangeSvc.CreateImplicitInvitation(inviter.Label, inviter.DID, invitee.Label, invitee.DID, nil)
}
func (c *Client) QueryConnections(request *QueryConnectionsParams) ([]*Connection, error) {  
	records, err := c.connectionStore.QueryConnectionRecords()
	if err != nil {
		return nil, fmt.Errorf("failed query connections: %w", err)
	}
	var result []*Connection
	for _, record := range records {
		if request.State != "" && request.State != record.State {
			continue
		}
		if request.InvitationID != "" && request.InvitationID != record.InvitationID {
			continue
		}
		if request.ParentThreadID != "" && request.ParentThreadID != record.ParentThreadID {
			continue
		}
		if request.MyDID != "" && request.MyDID != record.MyDID {
			continue
		}
		if request.TheirDID != "" && request.TheirDID != record.TheirDID {
			continue
		}
		result = append(result, &Connection{Record: record})
	}
	return result, nil
}
func (c *Client) GetConnection(connectionID string) (*Connection, error) {
	conn, err := c.connectionStore.GetConnectionRecord(connectionID)
	if err != nil {
		if errors.Is(err, storage.ErrDataNotFound) {
			return nil, ErrConnectionNotFound
		}
		return nil, fmt.Errorf("cannot fetch state from store: connectionid=%s err=%w", connectionID, err)
	}
	return &Connection{
		conn,
	}, nil
}
func (c *Client) GetConnectionAtState(connectionID, stateID string) (*Connection, error) {
	conn, err := c.connectionStore.GetConnectionRecordAtState(connectionID, stateID)
	if err != nil {
		if errors.Is(err, storage.ErrDataNotFound) {
			return nil, ErrConnectionNotFound
		}
		return nil, fmt.Errorf("cannot fetch state from store: connectionid=%s err=%w", connectionID, err)
	}
	return &Connection{
		conn,
	}, nil
}
func (c *Client) CreateConnection(myDID string, theirDID *did.Doc, options ...ConnectionOption) (string, error) {
	conn := &Connection{&connection.Record{
		ConnectionID: uuid.New().String(),
		State:        connection.StateNameCompleted,
		TheirDID:     theirDID.ID,
		MyDID:        myDID,
		Namespace:    connection.MyNSPrefix,
	}}
	for i := range options {
		options[i](conn)
	}
	destination, err := service.CreateDestination(theirDID)
	if err != nil {
		return "", fmt.Errorf("createConnection: failed to create destination: %w", err)
	}
	conn.ServiceEndPoint = destination.ServiceEndpoint
	conn.RecipientKeys = destination.RecipientKeys
	conn.RoutingKeys = destination.RoutingKeys
	err = c.didexchangeSvc.CreateConnection(conn.Record, theirDID)
	if err != nil {
		return "", fmt.Errorf("createConnection: err: %w", err)
	}
	return conn.ConnectionID, nil
}
func (c *Client) RemoveConnection(connectionID string) error {
	err := c.connectionStore.RemoveConnection(connectionID)
	if err != nil {
		return fmt.Errorf("cannot remove connection from the store: err=%w", err)
	}
	return nil
}
type ConnectionOption func(*Connection)
func WithTheirLabel(l string) ConnectionOption {
	return func(c *Connection) {
		c.TheirLabel = l
	}
}
func WithThreadID(thid string) ConnectionOption {
	return func(c *Connection) {
		c.ThreadID = thid
	}
}
func WithParentThreadID(pthid string) ConnectionOption {
	return func(c *Connection) {
		c.ParentThreadID = pthid
	}
}
func WithInvitationID(id string) ConnectionOption {
	return func(c *Connection) {
		c.InvitationID = id
	}
}