package wallet

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

func (s *Service) ReconcileExternalRechargeOrders(ctx context.Context, appCode string, limit int) (int, error) {
	if s.repository == nil {
		return 0, xerr.New(xerr.Unavailable, "wallet repository is not configured")
	}
	if limit <= 0 {
		return 0, nil
	}
	appCode = strings.ToLower(strings.TrimSpace(appCode))
	orders, err := s.repository.ListExternalRechargeOrdersForReconcile(ctx, appCode, limit)
	if err != nil {
		return 0, err
	}
	processed := 0
	for _, order := range orders {
		// 跨租户扫描后必须恢复订单自己的 context，后续幂等流水和账户更新不能落到默认 lalu。
		orderCtx := appcode.WithContext(ctx, order.AppCode)
		if _, err := s.refreshMifaPayRechargeOrder(orderCtx, order); err != nil {
			processed++
			continue
		}
		if _, err := s.refreshV5PayRechargeOrder(orderCtx, order); err != nil {
			processed++
			continue
		}
		processed++
	}
	return processed, nil
}

func (s *Service) refreshMifaPayRechargeOrder(ctx context.Context, order ledger.ExternalRechargeOrder) (ledger.ExternalRechargeOrder, error) {
	if s.mifaPay == nil || order.ProviderCode != ledger.PaymentProviderMifaPay || isExternalRechargeTerminalStatus(order.Status) {
		return order, nil
	}
	query, err := s.mifaPay.QueryOrder(ctx, MifaPayQueryOrderRequest{
		OrderID:          order.OrderID,
		ProviderOrderID:  order.ProviderOrderID,
		OrderCreatedAtMS: order.CreatedAtMS,
	})
	if err != nil {

		return order, err
	}
	providerOrderID := firstNonEmpty(query.ProviderOrderID, order.ProviderOrderID)
	data := MifaPayNotifyData{
		OrderID:         firstNonEmpty(query.OrderID, order.OrderID),
		ProviderOrderID: providerOrderID,
		Amount:          query.Amount,
		Currency:        query.Currency,
		PayType:         query.PayType,
		RawJSON:         query.RawJSON,
	}
	switch strings.TrimSpace(query.Status) {
	case "1":
		if !mifaPayQueryMatchesOrder(data, order) {

			return s.repository.MarkExternalRechargeOrderFailed(ctx, order.AppCode, order.OrderID, "mifapay query order data mismatch", query.RawJSON)
		}
		if isTemporaryExternalRechargeOrder(order) {
			return s.repository.MarkExternalRechargeOrderPaid(ctx, order.AppCode, order.OrderID, providerOrderID, query.RawJSON)
		}
		return s.repository.CreditExternalRechargeOrder(ctx, order.AppCode, order.OrderID, providerOrderID, "", query.RawJSON)
	case "4":
		return s.repository.MarkExternalRechargeOrderFailed(ctx, order.AppCode, order.OrderID, "mifapay order status 4", query.RawJSON)
	case "0", "5", "":
		return order, nil
	default:
		return order, nil
	}
}

func (s *Service) refreshV5PayRechargeOrder(ctx context.Context, order ledger.ExternalRechargeOrder) (ledger.ExternalRechargeOrder, error) {
	if s.v5Pay == nil || order.ProviderCode != ledger.PaymentProviderV5Pay || isExternalRechargeTerminalStatus(order.Status) {
		return order, nil
	}
	query, err := s.v5Pay.QueryOrder(ctx, V5PayQueryOrderRequest{
		OrderID:         order.OrderID,
		ProviderOrderID: order.ProviderOrderID,
		CountryCode:     order.CountryCode,
		CurrencyCode:    order.CurrencyCode,
	})
	if err != nil {

		return order, err
	}
	providerOrderID := firstNonEmpty(query.ProviderOrderID, order.ProviderOrderID)
	data := V5PayNotifyData{
		OrderID:         firstNonEmpty(query.OrderID, order.OrderID),
		ProviderOrderID: providerOrderID,
		OrderStatus:     query.Status,
		Amount:          query.Amount,
		Currency:        query.Currency,
		ProductType:     query.ProductType,
		RawJSON:         query.RawJSON,
	}
	switch strings.TrimSpace(query.Status) {
	case "2":
		if !v5PayOrderDataMatchesOrder(data, order) {

			return s.repository.MarkExternalRechargeOrderFailed(ctx, order.AppCode, order.OrderID, "v5pay query order data mismatch", query.RawJSON)
		}
		if isTemporaryExternalRechargeOrder(order) {
			return s.repository.MarkExternalRechargeOrderPaid(ctx, order.AppCode, order.OrderID, providerOrderID, query.RawJSON)
		}
		return s.repository.CreditExternalRechargeOrder(ctx, order.AppCode, order.OrderID, providerOrderID, "", query.RawJSON)
	case "3", "5", "6":
		return s.repository.MarkExternalRechargeOrderFailed(ctx, order.AppCode, order.OrderID, "v5pay order status "+query.Status, query.RawJSON)
	case "0", "1", "":
		return order, nil
	default:
		return order, nil
	}
}

func isExternalRechargeTerminalStatus(status string) bool {
	switch strings.TrimSpace(status) {
	case ledger.ExternalRechargeStatusCredited, ledger.ExternalRechargeStatusPaid, ledger.ExternalRechargeStatusFailed:
		return true
	default:
		return false
	}
}
