package runtimeapi

import (
	"context"
	"errors"

	semantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/identityv1"
	runtimev1 "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/runtime/v1"
	"github.com/pingcap-inc/nexuscrm-contract/wire-go/mapping"
)

type IdentityExchange func(context.Context, semantic.Request) (semantic.Response, error)

type IdentityServer struct {
	runtimev1.UnimplementedIdentityContextServiceServer
	exchange IdentityExchange
}

func NewIdentityServer(exchange IdentityExchange) (*IdentityServer, error) {
	if exchange == nil {
		return nil, errors.New("runtime-api identity exchange is required")
	}
	return &IdentityServer{exchange: exchange}, nil
}

func (s *IdentityServer) Exchange(ctx context.Context, request *runtimev1.ExchangeRequest) (*runtimev1.ExchangeResponse, error) {
	if s == nil || s.exchange == nil {
		return nil, mapping.ToIdentityStatusError(&semantic.Failure{Category: semantic.FailureUnavailable})
	}
	semanticRequest, err := mapping.FromWireIdentityExchangeRequest(ctx, request)
	if err != nil {
		return nil, mapping.ToIdentityStatusError(err)
	}
	response, err := s.exchange(ctx, semanticRequest)
	if err != nil {
		return nil, mapping.ToIdentityStatusError(err)
	}
	wireResponse, err := mapping.ToWireIdentityExchangeResponse(response)
	if err != nil {
		return nil, mapping.ToIdentityStatusError(err)
	}
	return wireResponse, nil
}
