package wallet

import (
	"context"
	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	"hyapp/services/wallet-service/internal/domain/ledger"
	"strings"
)

// sharedPaymentConfigAppCode 是三方收单方式的唯一国家/币种配置 owner。
// Yumi、Aslan 等 App 可以有自己的商品和用户区域，但不能复制一套 V5Pay/MiFaPay
// 国家、币种或汇率配置，否则人工收款与 H5 下单会因配置漂移得到不同的支付结果。
const sharedPaymentConfigAppCode = appcode.Default

func usesSharedPaymentConfig(providerCode string) bool {
	switch ledger.NormalizePaymentProvider(providerCode) {
	case ledger.PaymentProviderMifaPay, ledger.PaymentProviderV5Pay:
		return true
	default:
		return false
	}
}

// ListThirdPartyPaymentChannels 返回后台三方支付管理页需要的渠道、国家和方式树。
func (s *Service) ListThirdPartyPaymentChannels(ctx context.Context, query ledger.ListThirdPartyPaymentChannelsQuery) ([]ledger.ThirdPartyPaymentChannel, error) {
	if s.repository == nil {
		return nil, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	query.AppCode = appcode.Normalize(query.AppCode)
	if strings.TrimSpace(query.Status) != "" {
		query.Status = ledger.NormalizeThirdPartyPaymentStatus(query.Status)
		if query.Status == "" {
			return nil, xerr.New(xerr.InvalidArgument, "status is invalid")
		}
	}
	// 指定渠道时，V5Pay/MiFaPay 的国家和币种统一由 Lalu 维护。读取端始终切到
	// 该配置 owner，避免某个 App 没有复制支付方式时，临时链接和人工查单退化为无候选可用。
	if usesSharedPaymentConfig(query.ProviderCode) {
		query.AppCode = sharedPaymentConfigAppCode
		ctx = appcode.WithContext(ctx, query.AppCode)
		return s.repository.ListThirdPartyPaymentChannels(ctx, query)
	}
	ctx = appcode.WithContext(ctx, query.AppCode)
	channels, err := s.repository.ListThirdPartyPaymentChannels(ctx, query)
	if err != nil || query.AppCode == sharedPaymentConfigAppCode || query.ProviderCode != "" {
		return channels, err
	}

	// 未指定渠道的临时收款页面仍要同时展示两个共享渠道。保留当前 App 的非共享渠道，
	// 但移除其历史副本，确保 UI 不会把同一国家/币种配置展示为两套来源。
	filtered := make([]ledger.ThirdPartyPaymentChannel, 0, len(channels)+2)
	for _, channel := range channels {
		if !usesSharedPaymentConfig(channel.ProviderCode) {
			filtered = append(filtered, channel)
		}
	}
	for _, providerCode := range []string{ledger.PaymentProviderMifaPay, ledger.PaymentProviderV5Pay} {
		sharedQuery := query
		sharedQuery.AppCode = sharedPaymentConfigAppCode
		sharedQuery.ProviderCode = providerCode
		sharedCtx := appcode.WithContext(ctx, sharedPaymentConfigAppCode)
		sharedChannels, err := s.repository.ListThirdPartyPaymentChannels(sharedCtx, sharedQuery)
		if err != nil {
			return nil, err
		}
		filtered = append(filtered, sharedChannels...)
	}
	return filtered, nil
}

// sharedPaymentMethod 返回支付配置 owner 的方式。订单本身仍按 command.AppCode 落库，
// 因此只共享国家/币种、产品类型和汇率，不会把 Yumi/Aslan 的账务事实写入 Lalu。
func (s *Service) sharedPaymentMethod(ctx context.Context, appCode string, providerCode string, methodID int64) (ledger.ThirdPartyPaymentMethod, error) {
	configAppCode := appcode.Normalize(appCode)
	if usesSharedPaymentConfig(providerCode) {
		configAppCode = sharedPaymentConfigAppCode
	}
	return s.repository.GetThirdPartyPaymentMethod(ctx, configAppCode, methodID)
}

func (s *Service) SetThirdPartyPaymentMethodStatus(ctx context.Context, command ledger.ThirdPartyPaymentMethodStatusCommand) (ledger.ThirdPartyPaymentMethod, error) {
	if command.MethodID <= 0 || command.OperatorUserID <= 0 {
		return ledger.ThirdPartyPaymentMethod{}, xerr.New(xerr.InvalidArgument, "payment method and operator are required")
	}
	if s.repository == nil {
		return ledger.ThirdPartyPaymentMethod{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	command.AppCode = appcode.Normalize(command.AppCode)
	ctx = appcode.WithContext(ctx, command.AppCode)
	return s.repository.SetThirdPartyPaymentMethodStatus(ctx, command)
}

func (s *Service) UpdateThirdPartyPaymentRate(ctx context.Context, command ledger.ThirdPartyPaymentRateCommand) (ledger.ThirdPartyPaymentMethod, error) {
	command.AppCode = appcode.Normalize(command.AppCode)
	command.USDToCurrencyRate = strings.TrimSpace(command.USDToCurrencyRate)
	if command.MethodID <= 0 || command.OperatorUserID <= 0 || !validNonNegativeDecimal(command.USDToCurrencyRate) {
		return ledger.ThirdPartyPaymentMethod{}, xerr.New(xerr.InvalidArgument, "payment rate command is invalid")
	}
	if s.repository == nil {
		return ledger.ThirdPartyPaymentMethod{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	ctx = appcode.WithContext(ctx, command.AppCode)
	return s.repository.UpdateThirdPartyPaymentRate(ctx, command)
}

// ListH5RechargeOptions 只返回目标用户当前可买商品和已配置汇率的支付方式。
func (s *Service) ListH5RechargeOptions(ctx context.Context, query ledger.H5RechargeOptionsQuery) (ledger.H5RechargeOptions, error) {
	query.AppCode = appcode.Normalize(query.AppCode)
	query.AudienceType = ledger.NormalizeRechargeAudienceType(query.AudienceType)
	query.TargetCountryCode = strings.ToUpper(strings.TrimSpace(query.TargetCountryCode))
	if query.TargetUserID <= 0 || query.TargetRegionID <= 0 || query.AudienceType == "" {
		return ledger.H5RechargeOptions{}, xerr.New(xerr.InvalidArgument, "h5 recharge options query is incomplete")
	}
	if s.repository == nil {
		return ledger.H5RechargeOptions{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	ctx = appcode.WithContext(ctx, query.AppCode)
	options, err := s.repository.ListH5RechargeOptions(ctx, query)
	if err != nil {
		return ledger.H5RechargeOptions{}, err
	}
	if s.mifaPay == nil && s.v5Pay == nil {
		options.PaymentMethods = nil
	} else {
		filtered := options.PaymentMethods[:0]
		for _, method := range options.PaymentMethods {

			if method.ProviderCode == ledger.PaymentProviderMifaPay && s.mifaPay != nil {
				filtered = append(filtered, method)
			}
			if method.ProviderCode == ledger.PaymentProviderV5Pay && s.v5Pay != nil {
				filtered = append(filtered, method)
			}
		}
		options.PaymentMethods = s.filterV5PayRuntimeProductTypes(ctx, filtered)
	}
	usdtTRC20Address := s.externalRecharge.usdtTRC20AddressForApp(query.AppCode)
	options.USDTTRC20Enabled = s.externalRecharge.USDTTRC20Enabled && usdtTRC20Address != ""
	options.USDTTRC20Address = usdtTRC20Address
	return options, nil
}

func (s *Service) filterV5PayRuntimeProductTypes(ctx context.Context, methods []ledger.ThirdPartyPaymentMethod) []ledger.ThirdPartyPaymentMethod {
	if s.v5Pay == nil || len(methods) == 0 {
		return methods
	}
	type productKey struct {
		country  string
		currency string
	}
	allowedByKey := map[productKey]map[string]bool{}
	filtered := methods[:0]
	for _, method := range methods {
		if method.ProviderCode != ledger.PaymentProviderV5Pay {
			filtered = append(filtered, method)
			continue
		}
		key := productKey{country: strings.ToUpper(strings.TrimSpace(method.CountryCode)), currency: strings.ToUpper(strings.TrimSpace(method.CurrencyCode))}
		allowed, ok := allowedByKey[key]
		if !ok {
			allowed = map[string]bool{}
			products, err := s.v5Pay.ListProductTypes(ctx, V5PayProductTypesRequest{CountryCode: key.country, CurrencyCode: key.currency})
			if err == nil {
				for _, product := range products.PayinList {

					if product.SupportCashierMode == 0 {
						continue
					}
					if product.Currency != "" && !strings.EqualFold(product.Currency, key.currency) {
						continue
					}
					if productType := strings.ToUpper(strings.TrimSpace(product.ProductType)); productType != "" {
						allowed[productType] = true
					}
				}
			}
			allowedByKey[key] = allowed
		}
		if allowed[strings.ToUpper(strings.TrimSpace(method.PayType))] {
			filtered = append(filtered, method)
		}
	}
	return filtered
}
