package pay

import (
	"context"
	"database/sql"
	"net/http"
	"strings"
	"time"
	"tydata-server/app/main/api/internal/svc"
	"tydata-server/app/main/model"
	"tydata-server/common/globalkey"

	"github.com/Masterminds/squirrel"
	"github.com/pkg/errors"
	"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

// HandleCommissionAndWalletDeduction 处理退款后的佣金状态更新和钱包金额扣除
// 这是一个公共函数，可以被支付宝和微信退款逻辑共享使用
// 只有当订单状态不为已退款时，才会处理佣金状态更新和钱包金额扣除
func HandleCommissionAndWalletDeduction(ctx context.Context, svcCtx *svc.ServiceContext, session sqlx.Session, order *model.Order) error {
	// 查询非已退款的佣金
	commissionBuilder := svcCtx.AgentCommissionModel.SelectBuilder()
	commissions, commissionsErr := svcCtx.AgentCommissionModel.FindAll(ctx, commissionBuilder.Where(squirrel.And{
		squirrel.Eq{"order_id": order.Id},
		squirrel.NotEq{"status": 2}, // 只查询非已退款的佣金
	}), "")
	if commissionsErr != nil {
		logx.Errorf("查询代理佣金失败，订单ID: %d, 错误: %v", order.Id, commissionsErr)
		return nil // 返回 nil，因为佣金更新失败不应影响退款流程
	}

	for _, commission := range commissions {
		// 记录更新佣金状态前的状态值，用于后续判断
		oldCommissionStatus := commission.Status
		commission.Status = 2 // 设置为已退款

		// 更新佣金状态到数据库
		var updateCommissionErr error
		if session != nil {
			updateCommissionErr = svcCtx.AgentCommissionModel.UpdateWithVersion(ctx, session, commission)
		} else {
			updateCommissionErr = svcCtx.AgentCommissionModel.UpdateWithVersion(ctx, nil, commission)
		}
		if updateCommissionErr != nil {
			logx.Errorf("更新代理佣金状态失败，佣金ID: %d, 订单ID: %d, 错误: %v", commission.Id, order.Id, updateCommissionErr)
			continue // 如果佣金状态更新失败，就不继续处理钱包
		}

		// 处理用户钱包的金额扣除
		wallet, err := svcCtx.AgentWalletModel.FindOneByAgentId(ctx, commission.AgentId)
		if err != nil {
			logx.Errorf("查询代理钱包失败，代理ID: %d, 错误: %v", commission.AgentId, err)
			continue
		}

		// 记录变动前的余额
		balanceBefore := wallet.Balance
		frozenBalanceBefore := wallet.FrozenBalance

		// 如果是冻结状态的佣金，直接扣减冻结余额
		if oldCommissionStatus == 1 {
			// 冻结状态的佣金，根据订单金额优先减少冻结金额，如果冻结金额不足则减少钱包余额
			if wallet.FrozenBalance >= order.Amount {
				// 冻结余额足够，优先减少冻结金额
				wallet.FrozenBalance -= order.Amount
			} else {
				// 冻结余额不足，先扣减所有冻结金额，再扣减余额
				remaining := order.Amount - wallet.FrozenBalance
				wallet.FrozenBalance = 0
				wallet.Balance -= remaining
			}
			// 其他状态的佣金，比如已结算状态（status = 0），直接扣减钱包余额
		} else {
			wallet.Balance -= order.Amount
		}
		// 变动后余额和冻结余额
		balanceAfter := wallet.Balance
		frozenBalanceAfter := wallet.FrozenBalance
		// 更新钱包
		var updateWalletErr error
		if session != nil {
			updateWalletErr = svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet)
		} else {
			updateWalletErr = svcCtx.AgentWalletModel.UpdateWithVersion(ctx, nil, wallet)
		}
		if updateWalletErr != nil {
			logx.Errorf("更新代理钱包失败，代理ID: %d, 错误: %v", commission.AgentId, updateWalletErr)
			continue
		}
		// 创建钱包交易流水记录（退款）
		transErr := svcCtx.AgentService.CreateWalletTransaction(
			ctx,
			session,
			commission.AgentId,
			model.WalletTransactionTypeRefund,
			-order.Amount,
			balanceBefore,
			balanceAfter,
			frozenBalanceBefore,
			frozenBalanceAfter,
			order.OrderNo,
			commission.Id,
			"订单退款，佣金已扣除",
		)
		if transErr != nil {
			logx.Errorf("创建代理钱包流水记录失败，代理ID: %d, 错误: %v", commission.AgentId, transErr)
			continue
		}

	}
	return nil
}

type WechatPayRefundCallbackLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewWechatPayRefundCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WechatPayRefundCallbackLogic {
	return &WechatPayRefundCallbackLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

// handleQueryOrderRefund 处理查询订单退款
func (l *WechatPayRefundCallbackLogic) handleQueryOrderRefund(orderNo string, status refunddomestic.Status) error {
	order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, orderNo)
	if err != nil {
		return errors.Wrapf(err, "查找查询订单信息失败: %s", orderNo)
	}

	// 检查订单是否已经处理过退款
	if order.Status == model.OrderStatusRefunded {
		logx.Infof("订单已经是退款状态，无需重复处理: orderNo=%s", orderNo)
		return nil
	}

	// 只处理成功和失败状态
	var orderStatus, refundStatus string
	switch status {
	case refunddomestic.STATUS_SUCCESS:
		orderStatus = model.OrderStatusRefunded
		refundStatus = model.OrderRefundStatusSuccess
	case refunddomestic.STATUS_CLOSED:
		// 退款关闭，保持订单原状态，更新退款记录为失败
		refundStatus = model.OrderRefundStatusFailed
	case refunddomestic.STATUS_ABNORMAL:
		// 退款异常，保持订单原状态，更新退款记录为失败
		refundStatus = model.OrderRefundStatusFailed
	default:
		// 其他状态暂不处理
		return nil
	}

	// 使用事务同时更新订单和退款记录
	err = l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
		// 更新订单状态（仅在退款成功时更新）
		if status == refunddomestic.STATUS_SUCCESS {
			order.Status = orderStatus
			order.RefundTime = sql.NullTime{
				Time:  time.Now(),
				Valid: true,
			}
			if err := l.svcCtx.OrderModel.UpdateWithVersion(ctx, session, order); err != nil {
				return errors.Wrapf(err, "更新查询订单状态失败: %s", orderNo)
			}

			// 退款成功时，更新代理佣金状态并扣除钱包金额
			HandleCommissionAndWalletDeduction(ctx, l.svcCtx, session, order)
		}

		// 查找最新的pending状态的退款记录
		refund, err := l.findLatestPendingRefund(ctx, order.Id)
		if err != nil {
			if err == model.ErrNotFound {
				logx.Errorf("未找到订单对应的待处理退款记录: orderNo=%s, orderId=%d", orderNo, order.Id)
				return nil // 没有退款记录时不报错，只记录警告
			}
			return errors.Wrapf(err, "查找退款记录失败: orderNo=%s", orderNo)
		}

		// 检查退款记录是否已经处理过
		if refund.Status == model.OrderRefundStatusSuccess {
			logx.Infof("退款记录已经是成功状态，无需重复处理: orderNo=%s, refundId=%d", orderNo, refund.Id)
			return nil
		}

		refund.Status = refundStatus
		if status == refunddomestic.STATUS_SUCCESS {
			refund.RefundTime = sql.NullTime{
				Time:  time.Now(),
				Valid: true,
			}
		} else if status == refunddomestic.STATUS_CLOSED {
			refund.CloseTime = sql.NullTime{
				Time:  time.Now(),
				Valid: true,
			}
		}

		if _, err := l.svcCtx.OrderRefundModel.Update(ctx, session, refund); err != nil {
			return errors.Wrapf(err, "更新退款记录状态失败: orderNo=%s", orderNo)
		}

		return nil
	})

	if err != nil {
		return errors.Wrapf(err, "更新订单和退款记录失败: %s", orderNo)
	}

	return nil
}

// handleAgentOrderRefund 处理代理会员订单退款
func (l *WechatPayRefundCallbackLogic) handleAgentOrderRefund(orderNo string, status refunddomestic.Status) error {
	order, err := l.svcCtx.AgentMembershipRechargeOrderModel.FindOneByOrderNo(l.ctx, orderNo)
	if err != nil {
		return errors.Wrapf(err, "查找代理会员订单信息失败: %s", orderNo)
	}

	// 检查订单是否已经处理过退款
	if order.Status == "refunded" {
		logx.Infof("代理会员订单已经是退款状态，无需重复处理: orderNo=%s", orderNo)
		return nil
	}

	if status == refunddomestic.STATUS_SUCCESS {
		order.Status = "refunded"
	} else if status == refunddomestic.STATUS_ABNORMAL {
		return nil // 异常状态直接返回
	} else {
		return nil // 其他状态直接返回
	}

	if err := l.svcCtx.AgentMembershipRechargeOrderModel.UpdateWithVersion(l.ctx, nil, order); err != nil {
		return errors.Wrapf(err, "更新代理会员订单状态失败: %s", orderNo)
	}

	return nil
}

// sendSuccessResponse 发送成功响应
func (l *WechatPayRefundCallbackLogic) sendSuccessResponse(w http.ResponseWriter) {
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write([]byte("success"))
}

func (l *WechatPayRefundCallbackLogic) WechatPayRefundCallback(w http.ResponseWriter, r *http.Request) error {
	// 1. 处理微信退款通知
	notification, err := l.svcCtx.WechatPayService.HandleRefundNotification(l.ctx, r)
	if err != nil {
		logx.Errorf("微信退款回调处理失败: %v", err)
		l.sendSuccessResponse(w)
		return nil
	}

	// 2. 检查关键字段是否为空
	if notification.OutTradeNo == nil {
		logx.Errorf("微信退款回调OutTradeNo字段为空")
		l.sendSuccessResponse(w)
		return nil
	}

	orderNo := *notification.OutTradeNo

	// 3. 判断退款状态，优先使用Status，如果Status为nil则使用SuccessTime判断
	var status refunddomestic.Status
	var statusDetermined bool = false

	if notification.Status != nil {
		status = *notification.Status
		statusDetermined = true
	} else if notification.SuccessTime != nil && !notification.SuccessTime.IsZero() {
		// 如果Status为空但SuccessTime有值，说明退款成功
		status = refunddomestic.STATUS_SUCCESS
		statusDetermined = true
	} else {
		logx.Errorf("微信退款回调Status和SuccessTime都为空，无法确定退款状态: orderNo=%s", orderNo)
		l.sendSuccessResponse(w)
		return nil
	}

	if !statusDetermined {
		logx.Errorf("微信退款回调无法确定退款状态: orderNo=%s", orderNo)
		l.sendSuccessResponse(w)
		return nil
	}

	var processErr error

	// 4. 根据订单号前缀处理不同类型的订单
	switch {
	case strings.HasPrefix(orderNo, "Q_"):
		processErr = l.handleQueryOrderRefund(orderNo, status)
	case strings.HasPrefix(orderNo, "A_"):
		processErr = l.handleAgentOrderRefund(orderNo, status)
	default:
		// 兼容旧订单，假设没有前缀的是查询订单
		processErr = l.handleQueryOrderRefund(orderNo, status)
	}

	// 5. 处理错误并响应
	if processErr != nil {
		logx.Errorf("处理退款订单失败: orderNo=%s, err=%v", orderNo, processErr)
	}

	// 无论处理是否成功，都返回成功响应给微信
	l.sendSuccessResponse(w)
	return nil
}

// findLatestPendingRefund 查找订单最新的pending状态退款记录
func (l *WechatPayRefundCallbackLogic) findLatestPendingRefund(ctx context.Context, orderId int64) (*model.OrderRefund, error) {
	// 使用SelectBuilder查询最新的pending状态退款记录
	builder := l.svcCtx.OrderRefundModel.SelectBuilder().
		Where("order_id = ? AND status = ? AND del_state = ?", orderId, model.OrderRefundStatusPending, globalkey.DelStateNo).
		OrderBy("id DESC").
		Limit(1)

	refunds, err := l.svcCtx.OrderRefundModel.FindAll(ctx, builder, "")
	if err != nil {
		return nil, err
	}

	if len(refunds) == 0 {
		return nil, model.ErrNotFound
	}

	return refunds[0], nil
}
