package quotation_service_v2

import (
	"context"
	"strings"
	"time"

	"github.com/tech/sendico/payments/quotation/internal/service/quotation/batch_quote_processor_v2"
	"github.com/tech/sendico/payments/quotation/internal/service/quotation/quote_computation_service"
	"github.com/tech/sendico/payments/quotation/internal/service/quotation/quote_executability_classifier"
	"github.com/tech/sendico/payments/quotation/internal/service/quotation/quote_idempotency_service"
	"github.com/tech/sendico/payments/quotation/internal/service/quotation/quote_persistence_service"
	quote_request_validator_v2 "github.com/tech/sendico/payments/quotation/internal/service/quotation/quote_request_validator"
	"github.com/tech/sendico/payments/quotation/internal/service/quotation/quote_response_mapper_v2"
	"github.com/tech/sendico/payments/quotation/internal/service/quotation/transfer_intent_hydrator"
	quotestorage "github.com/tech/sendico/payments/storage/quote"
	"github.com/tech/sendico/pkg/merrors"
	"github.com/tech/sendico/pkg/mlogger"
	quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
	"go.mongodb.org/mongo-driver/v2/bson"
)

type Dependencies struct {
	Logger         mlogger.Logger
	QuotesStore    quotestorage.QuotesStore
	Validator      *quote_request_validator_v2.QuoteRequestValidatorV2
	Hydrator       *transfer_intent_hydrator.TransferIntentHydrator
	Idempotency    *quote_idempotency_service.QuoteIdempotencyService
	Computation    *quote_computation_service.QuoteComputationService
	Classifier     *quote_executability_classifier.QuoteExecutabilityClassifier
	Persistence    *quote_persistence_service.QuotePersistenceService
	ResponseMapper *quote_response_mapper_v2.QuoteResponseMapperV2
	Now            func() time.Time
	NewRef         func() string
}

type QuotationServiceV2 struct {
	deps   Dependencies
	logger mlogger.Logger
	quotationv2.UnimplementedQuotationServiceServer
}

func New(deps Dependencies) *QuotationServiceV2 {
	if deps.Validator == nil {
		deps.Validator = quote_request_validator_v2.New()
	}
	if deps.Idempotency == nil {
		deps.Idempotency = quote_idempotency_service.New()
	}
	if deps.Classifier == nil {
		deps.Classifier = quote_executability_classifier.New()
	}
	if deps.Persistence == nil {
		deps.Persistence = quote_persistence_service.New()
	}
	if deps.ResponseMapper == nil {
		deps.ResponseMapper = quote_response_mapper_v2.New()
	}
	if deps.Now == nil {
		deps.Now = time.Now
	}
	if deps.NewRef == nil {
		deps.NewRef = func() string { return bson.NewObjectID().Hex() }
	}
	if deps.Logger == nil {
		panic("quotation_service_v2: logger is required")
	}
	return &QuotationServiceV2{
		deps:   deps,
		logger: deps.Logger.Named("v2"),
	}
}

func (s *QuotationServiceV2) QuotePayment(ctx context.Context, req *quotationv2.QuotePaymentRequest) (*quotationv2.QuotePaymentResponse, error) {
	result, err := s.ProcessQuotePayment(ctx, req)
	if err != nil {
		return nil, err
	}
	return result.Response, nil
}

func (s *QuotationServiceV2) QuotePayments(ctx context.Context, req *quotationv2.QuotePaymentsRequest) (*quotationv2.QuotePaymentsResponse, error) {
	result, err := s.ProcessQuotePayments(ctx, req)
	if err != nil {
		return nil, err
	}
	return result.Response, nil
}

func (s *QuotationServiceV2) validateDependencies() error {
	if s == nil {
		return merrors.InvalidArgument("service is required")
	}
	if s.deps.QuotesStore == nil {
		return merrors.InvalidArgument("quotes store is required")
	}
	if s.deps.Validator == nil {
		return merrors.InvalidArgument("validator is required")
	}
	if s.deps.Hydrator == nil {
		return merrors.InvalidArgument("transfer intent hydrator is required")
	}
	if s.deps.Computation == nil {
		return merrors.InvalidArgument("quote computation service is required")
	}
	if s.deps.Idempotency == nil {
		return merrors.InvalidArgument("quote idempotency service is required")
	}
	if s.deps.Persistence == nil {
		return merrors.InvalidArgument("quote persistence service is required")
	}
	if s.deps.ResponseMapper == nil {
		return merrors.InvalidArgument("quote response mapper is required")
	}
	if s.deps.Classifier == nil {
		return merrors.InvalidArgument("quote executability classifier is required")
	}
	if s.deps.Now == nil {
		return merrors.InvalidArgument("now factory is required")
	}
	if s.deps.NewRef == nil {
		return merrors.InvalidArgument("ref factory is required")
	}
	return nil
}

func normalizeQuoteRef(value string) string {
	return strings.TrimSpace(value)
}

func newBatchContext(ctx *quote_request_validator_v2.Context) batch_quote_processor_v2.BatchContext {
	if ctx == nil {
		return batch_quote_processor_v2.BatchContext{}
	}
	return batch_quote_processor_v2.BatchContext{
		OrganizationRef:    strings.TrimSpace(ctx.OrganizationRef),
		OrganizationID:     ctx.OrganizationID,
		InitiatorRef:       strings.TrimSpace(ctx.InitiatorRef),
		PreviewOnly:        ctx.PreviewOnly,
		BaseIdempotencyKey: strings.TrimSpace(ctx.IdempotencyKey),
	}
}
