package pay

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

	"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"
)

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)
			}
		}

		// 查找最新的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)
		// 直接返回，避免旧订单影响
		processErr = nil
	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 string) (*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
}
