package quote_response_mapper_v2

import (
	"strings"

	qshared "github.com/tech/sendico/payments/quotation/internal/shared"
	feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
	moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
	paymentv1 "github.com/tech/sendico/pkg/proto/common/payment/v1"
	oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
	quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
	"google.golang.org/protobuf/proto"
)

func cloneMoney(src *moneyv1.Money) *moneyv1.Money {
	return qshared.CloneProtoMoneyTrim(src)
}

func cloneFeeLines(src []*feesv1.DerivedPostingLine) []*feesv1.DerivedPostingLine {
	if len(src) == 0 {
		return nil
	}
	result := make([]*feesv1.DerivedPostingLine, 0, len(src))
	for _, line := range src {
		if line == nil {
			result = append(result, nil)
			continue
		}
		cloned, ok := proto.Clone(line).(*feesv1.DerivedPostingLine)
		if !ok {
			continue
		}
		result = append(result, cloned)
	}
	if len(result) == 0 {
		return nil
	}
	return result
}

func cloneFeeRules(src []*feesv1.AppliedRule) []*feesv1.AppliedRule {
	if len(src) == 0 {
		return nil
	}
	result := make([]*feesv1.AppliedRule, 0, len(src))
	for _, rule := range src {
		if rule == nil {
			result = append(result, nil)
			continue
		}
		cloned, ok := proto.Clone(rule).(*feesv1.AppliedRule)
		if !ok {
			continue
		}
		result = append(result, cloned)
	}
	if len(result) == 0 {
		return nil
	}
	return result
}

func cloneFXQuote(src *oraclev1.Quote) *oraclev1.Quote {
	if src == nil {
		return nil
	}
	cloned, ok := proto.Clone(src).(*oraclev1.Quote)
	if !ok {
		return nil
	}
	return cloned
}

func cloneRoute(src *quotationv2.RouteSpecification) *quotationv2.RouteSpecification {
	if src == nil {
		return nil
	}
	result := &quotationv2.RouteSpecification{
		Rail:              strings.TrimSpace(src.GetRail()),
		Provider:          strings.TrimSpace(src.GetProvider()),
		PayoutMethod:      strings.TrimSpace(src.GetPayoutMethod()),
		Network:           strings.TrimSpace(src.GetNetwork()),
		RouteRef:          strings.TrimSpace(src.GetRouteRef()),
		PricingProfileRef: strings.TrimSpace(src.GetPricingProfileRef()),
		Settlement:        cloneRouteSettlement(src.GetSettlement()),
	}
	if hops := src.GetHops(); len(hops) > 0 {
		result.Hops = make([]*quotationv2.RouteHop, 0, len(hops))
		for _, hop := range hops {
			if hop == nil {
				continue
			}
			result.Hops = append(result.Hops, &quotationv2.RouteHop{
				Index:      hop.GetIndex(),
				Rail:       strings.TrimSpace(hop.GetRail()),
				Gateway:    strings.TrimSpace(hop.GetGateway()),
				InstanceId: strings.TrimSpace(hop.GetInstanceId()),
				Network:    strings.TrimSpace(hop.GetNetwork()),
				Role:       hop.GetRole(),
			})
		}
		if len(result.Hops) == 0 {
			result.Hops = nil
		}
	}
	return result
}

func cloneRouteSettlement(src *quotationv2.RouteSettlement) *quotationv2.RouteSettlement {
	if src == nil {
		return nil
	}
	result := &quotationv2.RouteSettlement{
		Model: strings.TrimSpace(src.GetModel()),
	}
	if asset := src.GetAsset(); asset != nil {
		key := asset.GetKey()
		result.Asset = &paymentv1.ChainAsset{
			Key: &paymentv1.ChainAssetKey{
				Chain:       strings.ToUpper(strings.TrimSpace(key.GetChain())),
				TokenSymbol: strings.ToUpper(strings.TrimSpace(key.GetTokenSymbol())),
			},
		}
		if contract := strings.TrimSpace(asset.GetContractAddress()); contract != "" {
			result.Asset.ContractAddress = &contract
		}
	}
	if result.Asset == nil && result.Model == "" {
		return nil
	}
	return result
}

func cloneExecutionConditions(src *quotationv2.ExecutionConditions) *quotationv2.ExecutionConditions {
	if src == nil {
		return nil
	}
	result := &quotationv2.ExecutionConditions{
		Readiness:                         src.GetReadiness(),
		BatchingEligible:                  src.GetBatchingEligible(),
		PrefundingRequired:                src.GetPrefundingRequired(),
		PrefundingCostIncluded:            src.GetPrefundingCostIncluded(),
		LiquidityCheckRequiredAtExecution: src.GetLiquidityCheckRequiredAtExecution(),
		LatencyHint:                       strings.TrimSpace(src.GetLatencyHint()),
	}
	if assumptions := src.GetAssumptions(); len(assumptions) > 0 {
		result.Assumptions = make([]string, 0, len(assumptions))
		for _, assumption := range assumptions {
			trimmed := strings.TrimSpace(assumption)
			if trimmed == "" {
				continue
			}
			result.Assumptions = append(result.Assumptions, trimmed)
		}
		if len(result.Assumptions) == 0 {
			result.Assumptions = nil
		}
	}
	return result
}
