package prmap

import (
	"strings"
	"time"

	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/agg"

	"github.com/tech/sendico/pkg/mlogger"
	orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
	"go.uber.org/zap"
)

type svc struct {
	logger mlogger.Logger
}

func (s *svc) Map(in MapInput) (out *MapOutput, err error) {
	logger := s.logger
	paymentRef := ""
	if in.Payment != nil {
		paymentRef = strings.TrimSpace(in.Payment.PaymentRef)
	}
	logger.Debug("Starting Map", zap.String("payment_ref", paymentRef))
	defer func(start time.Time) {
		fields := []zap.Field{
			zap.Int64("duration_ms", time.Since(start).Milliseconds()),
			zap.String("payment_ref", paymentRef),
		}
		if out != nil && out.Payment != nil {
			fields = append(fields,
				zap.String("state", out.Payment.GetState().String()),
				zap.Uint64("version", out.Payment.GetVersion()),
			)
		}
		if err != nil {
			logger.Warn("Failed to map", append(fields, zap.Error(err))...)
			return
		}
		logger.Debug("Completed Map", fields...)
	}(time.Now())

	if err := validateMapInput(in); err != nil {
		return nil, err
	}

	protoPayment, err := mapPayment(in.Payment)
	if err != nil {
		return nil, err
	}
	out = &MapOutput{Payment: protoPayment}
	return out, nil
}

func mapPayment(src *agg.Payment) (*orchestrationv2.Payment, error) {
	if src == nil {
		return nil, nil //nolint:nilnil // nil aggregate means no payment to map
	}

	intentSnapshot, err := mapIntentSnapshot(src.IntentSnapshot)
	if err != nil {
		return nil, err
	}
	quoteSnapshot := mapQuoteSnapshot(src.QuoteSnapshot, strings.TrimSpace(src.QuotationRef), strings.TrimSpace(src.IntentSnapshot.Ref))
	steps, err := mapStepExecutions(src.StepExecutions)
	if err != nil {
		return nil, err
	}

	return &orchestrationv2.Payment{
		PaymentRef:       strings.TrimSpace(src.PaymentRef),
		QuotationRef:     strings.TrimSpace(src.QuotationRef),
		IntentSnapshot:   intentSnapshot,
		QuoteSnapshot:    quoteSnapshot,
		ClientPaymentRef: strings.TrimSpace(src.ClientPaymentRef),
		State:            mapAggregateState(src.State),
		Version:          src.Version,
		StepExecutions:   steps,
		CreatedAt:        tsOrNil(src.CreatedAt),
		UpdatedAt:        tsOrNil(src.UpdatedAt),
	}, nil
}
