package pay

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
	"qnc-server/app/main/api/internal/svc"
	"qnc-server/app/main/api/internal/types"
	"qnc-server/app/main/model"
	"qnc-server/common/ctxdata"
	"qnc-server/common/xerr"
	"qnc-server/pkg/lzkit/lzUtils"

	"github.com/google/uuid"
	"github.com/pkg/errors"
	"github.com/redis/go-redis/v9"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

type PaymentLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}
type PaymentTypeResp struct {
	amount      float64
	outTradeNo  string
	description string
	orderID     string // 订单ID，用于开发环境测试支付模式
}

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

func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) {
	var paymentTypeResp *PaymentTypeResp
	var prepayData interface{}
	var orderID string

	// 检查是否为开发环境的测试支付模式
	env := os.Getenv("ENV")
	isDevTestPayment := env == "development" && (req.PayMethod == "test" || req.PayMethod == "test_empty")
	isEmptyReportMode := env == "development" && req.PayMethod == "test_empty"

	l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
		switch req.PayType {
		case "agent_vip":
			paymentTypeResp, err = l.AgentVipOrderPayment(req, session)
			if err != nil {
				return err
			}

		case "query":
			paymentTypeResp, err = l.QueryOrderPayment(req, session)
			if err != nil {
				return err
			}

		case "agent_upgrade":
			paymentTypeResp, err = l.AgentUpgradeOrderPayment(req, session)
			if err != nil {
				return err
			}
		}

		// 开发环境测试支付模式：跳过实际支付流程
		// 注意：订单状态更新在事务外进行，避免在事务中查询不到订单的问题
		if isDevTestPayment {
			// 获取订单ID（从 QueryOrderPayment 返回的 orderID）
			if paymentTypeResp.orderID == "" {
				return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "开发测试模式，订单ID无效")
			}
			orderID = paymentTypeResp.orderID

			// 在事务中只记录订单ID，不更新订单状态
			// 订单状态的更新和后续流程在事务提交后处理
			logx.Infof("开发环境测试支付模式：订单 %s (ID: %s) 将在事务提交后更新状态", paymentTypeResp.outTradeNo, orderID)

			// 返回测试支付标识
			prepayData = "test_payment_success"
			return nil
		}

		// 正常支付流程
		var createOrderErr error
		if req.PayMethod == "wechat" {
			prepayData, createOrderErr = l.svcCtx.WechatPayService.CreateWechatOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo)
		} else if req.PayMethod == "alipay" {
			prepayData, createOrderErr = l.svcCtx.AlipayService.CreateAlipayOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo)
		} else if req.PayMethod == "appleiap" {
			prepayData = l.svcCtx.ApplePayService.GetIappayAppID(paymentTypeResp.outTradeNo)
		}
		if createOrderErr != nil {
			return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 创建支付订单失败: %+v", createOrderErr)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	// 开发环境测试支付模式：事务提交后处理订单状态更新和后续流程
	if isDevTestPayment && paymentTypeResp != nil && paymentTypeResp.orderID != "" {
		// 使用 goroutine 异步处理，确保事务已完全提交
		go func() {
			// 短暂延迟，确保事务已完全提交到数据库
			time.Sleep(200 * time.Millisecond)

			finalOrderID := paymentTypeResp.orderID

			// 查找订单并更新状态为已支付
			order, findOrderErr := l.svcCtx.OrderModel.FindOne(context.Background(), finalOrderID)
			if findOrderErr != nil {
				logx.Errorf("开发测试模式，查找订单失败，订单ID: %s, 错误: %v", finalOrderID, findOrderErr)
				return
			}

			// 更新订单状态为已支付
			order.Status = "paid"
			now := time.Now()
			order.PayTime = sql.NullTime{Time: now, Valid: true}

			// 空报告模式：在 PaymentPlatform 字段中标记，用于后续生成空报告
			if isEmptyReportMode {
				order.PaymentPlatform = "test_empty"
				logx.Infof("开发环境空报告模式：订单 %s (ID: %s) 已标记为空报告模式", paymentTypeResp.outTradeNo, finalOrderID)
			}

			// 更新订单状态（在事务外执行）
			updateErr := l.svcCtx.OrderModel.UpdateWithVersion(context.Background(), nil, order)
			if updateErr != nil {
				logx.Errorf("开发测试模式，更新订单状态失败，订单ID: %s, 错误: %+v", finalOrderID, updateErr)
				return
			}

			logx.Infof("开发环境测试支付模式：订单 %s (ID: %s) 已自动标记为已支付", paymentTypeResp.outTradeNo, finalOrderID)

			// 再次短暂延迟，确保订单状态更新已提交
			time.Sleep(100 * time.Millisecond)

			// 根据订单类型处理后续流程
			if strings.HasPrefix(paymentTypeResp.outTradeNo, "U_") {
				// 升级订单：直接执行升级操作
				upgradeRecords, findUpgradeErr := l.svcCtx.AgentUpgradeModel.FindAll(context.Background(), l.svcCtx.AgentUpgradeModel.SelectBuilder().
					Where("order_no = ?", paymentTypeResp.outTradeNo).
					Limit(1), "")
				if findUpgradeErr != nil || len(upgradeRecords) == 0 {
					logx.Errorf("开发测试模式，查找升级记录失败，订单号: %s, 错误: %+v", paymentTypeResp.outTradeNo, findUpgradeErr)
					return
				}
				upgradeRecord := upgradeRecords[0]

				// 执行升级操作
				err := l.svcCtx.AgentWalletModel.Trans(context.Background(), func(transCtx context.Context, session sqlx.Session) error {
					if err := l.svcCtx.AgentService.ProcessUpgrade(transCtx, upgradeRecord.AgentId, upgradeRecord.ToLevel, upgradeRecord.UpgradeType, upgradeRecord.UpgradeFee, upgradeRecord.RebateAmount, paymentTypeResp.outTradeNo, ""); err != nil {
						return errors.Wrapf(err, "执行升级操作失败")
					}

					// 更新升级记录状态为已完成
					upgradeRecord.Status = 2 // 已完成（status: 1=待处理，2=已完成，3=已失败）
					upgradeRecord.Remark = lzUtils.StringToNullString("测试支付成功，升级完成")
					if updateErr := l.svcCtx.AgentUpgradeModel.UpdateWithVersion(transCtx, session, upgradeRecord); updateErr != nil {
						return errors.Wrapf(updateErr, "更新升级记录状态失败")
					}

					return nil
				})

				if err != nil {
					logx.Errorf("开发测试模式，处理升级订单失败，订单号: %s, 错误: %+v", paymentTypeResp.outTradeNo, err)
				} else {
					logx.Infof("开发测试模式，代理升级成功，订单号: %s, 代理ID: %s", paymentTypeResp.outTradeNo, upgradeRecord.AgentId)
				}
			} else {
				// 查询订单：发送支付成功通知任务，触发后续流程（生成报告和代理处理）
				if sendErr := l.svcCtx.AsynqService.SendQueryTask(finalOrderID); sendErr != nil {
					logx.Errorf("开发测试模式，发送支付成功通知任务失败，订单ID: %s, 错误: %+v", finalOrderID, sendErr)
				} else {
					logx.Infof("开发测试模式，已发送支付成功通知任务，订单ID: %s", finalOrderID)
				}
			}
		}()
	}

	switch v := prepayData.(type) {
	case string:
		// 如果 prepayData 是字符串类型，直接返回
		return &types.PaymentResp{PrepayId: v, OrderNo: paymentTypeResp.outTradeNo}, nil
	default:
		return &types.PaymentResp{PrepayData: prepayData, OrderNo: paymentTypeResp.outTradeNo}, nil
	}
}

func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) {
	userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
	if getUidErr != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取用户信息失败, %+v", getUidErr)
	}
	outTradeNo := req.Id
	redisKey := fmt.Sprintf(types.QueryCacheKey, userID, outTradeNo)
	cache, cacheErr := l.svcCtx.Redis.GetCtx(l.ctx, redisKey)
	if cacheErr != nil {
		if cacheErr == redis.Nil {
			return nil, errors.Wrapf(xerr.NewErrMsg("订单已过期"), "生成订单, 缓存不存在, %+v", cacheErr)
		}
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取缓存失败, %+v", cacheErr)
	}
	var data types.QueryCacheLoad
	err = json.Unmarshal([]byte(cache), &data)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解析缓存内容失败, %v", err)
	}

	product, err := l.svcCtx.ProductModel.FindOneByProductEn(l.ctx, data.Product)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 查找产品错误: %v", err)
	}

	var amount float64
	user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取用户信息失败: %v", err)
	}

	var agentLinkModel *model.AgentLink
	if data.AgentIdentifier != "" {
		var findAgentLinkErr error
		agentLinkModel, findAgentLinkErr = l.svcCtx.AgentLinkModel.FindOneByLinkIdentifier(l.ctx, data.AgentIdentifier)
		if findAgentLinkErr != nil {
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取代理链接失败: %+v", findAgentLinkErr)
		}
		amount = agentLinkModel.SetPrice
	} else {
		amount = product.SellPrice
	}

	if user.Inside == 1 {
		amount = 0.01
	}
	order := model.Order{
		Id:              uuid.NewString(),
		OrderNo:         outTradeNo,
		UserId:          userID,
		ProductId:       product.Id,
		PaymentPlatform: req.PayMethod,
		PaymentScene:    "app",
		Amount:          amount,
		Status:          "pending",
	}
	_, insertOrderErr := l.svcCtx.OrderModel.Insert(l.ctx, session, &order)
	if insertOrderErr != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存订单失败: %+v", insertOrderErr)
	}
	orderID := order.Id

	// 如果是代理推广订单，创建完整的代理订单记录
	if data.AgentIdentifier != "" && agentLinkModel != nil {
		// 获取代理信息
		agent, err := l.svcCtx.AgentModel.FindOne(l.ctx, agentLinkModel.AgentId)
		if err != nil {
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 查询代理信息失败: %+v", err)
		}

		// 获取产品配置（必须存在）
		productConfig, err := l.svcCtx.AgentProductConfigModel.FindOneByProductId(l.ctx, product.Id)
		if err != nil {
			if errors.Is(err, model.ErrNotFound) {
				return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单失败，产品配置不存在, productId: %s，请先在后台配置产品价格参数", product.Id)
			}
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 查询产品配置失败: %+v", err)
		}

		// 获取等级加成（需要从系统配置读取）
		levelBonus, err := l.getLevelBonus(agent.Level)
		if err != nil {
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取等级加成配置失败: %+v", err)
		}

		// 使用产品配置的底价计算实际底价
		basePrice := productConfig.BasePrice
		actualBasePrice := basePrice + float64(levelBonus)

		// 计算提价成本（使用产品配置）
		priceThreshold := 0.0
		priceFeeRate := 0.0
		if productConfig.PriceThreshold.Valid {
			priceThreshold = productConfig.PriceThreshold.Float64
		}
		if productConfig.PriceFeeRate.Valid {
			priceFeeRate = productConfig.PriceFeeRate.Float64
		}

		priceCost := 0.0
		if agentLinkModel.SetPrice > priceThreshold {
			priceCost = (agentLinkModel.SetPrice - priceThreshold) * priceFeeRate
		}

		// 计算代理收益
		agentProfit := agentLinkModel.SetPrice - actualBasePrice - priceCost

		// 创建代理订单记录
		agentOrder := model.AgentOrder{
			Id:              uuid.NewString(),
			AgentId:         agentLinkModel.AgentId,
			OrderId:         orderID,
			ProductId:       product.Id,
			OrderAmount:     amount,
			SetPrice:        agentLinkModel.SetPrice,
			ActualBasePrice: actualBasePrice,
			PriceCost:       priceCost,
			AgentProfit:     agentProfit,
			ProcessStatus:   0, // 待处理
		}
		_, agentOrderInsert := l.svcCtx.AgentOrderModel.Insert(l.ctx, session, &agentOrder)
		if agentOrderInsert != nil {
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理订单失败: %+v", agentOrderInsert)
		}
	}
	return &PaymentTypeResp{amount: amount, outTradeNo: outTradeNo, description: product.ProductName, orderID: orderID}, nil
}

// AgentVipOrderPayment 代理会员充值订单（已废弃，新系统使用升级功能替代）
func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) {
	// 新代理系统已废弃会员充值功能，请使用升级功能
	return nil, errors.Wrapf(xerr.NewErrMsg("该功能已废弃，请使用代理升级功能"), "")
}

// AgentUpgradeOrderPayment 代理升级订单支付
func (l *PaymentLogic) AgentUpgradeOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) {
	userID, err := ctxdata.GetUidFromCtx(l.ctx)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
	}

	// 1. 解析升级记录ID
	upgradeId := req.Id

	// 2. 查找升级记录
	upgradeRecord, err := l.svcCtx.AgentUpgradeModel.FindOne(l.ctx, upgradeId)
	if err != nil {
		if errors.Is(err, model.ErrNotFound) {
			return nil, errors.Wrapf(xerr.NewErrMsg("升级记录不存在"), "")
		}
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询升级记录失败, %v", err)
	}

	// 3. 验证升级记录状态（必须是待支付状态）
	if upgradeRecord.Status != 1 {
		return nil, errors.Wrapf(xerr.NewErrMsg("升级记录状态不正确，无法支付"), "")
	}

	// 4. 验证代理ID是否匹配
	agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
	}
	if agent.Id != upgradeRecord.AgentId {
		return nil, errors.Wrapf(xerr.NewErrMsg("无权支付此升级订单"), "")
	}

	// 5. 生成订单号（升级订单前缀 U_，限制长度不超过32）
	base := l.svcCtx.AlipayService.GenerateOutTradeNo()
	outTradeNo := "U_" + base
	if len(outTradeNo) > 32 {
		outTradeNo = outTradeNo[:32]
	}

	// 6. 获取用户信息（用于内部用户判断）
	user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取用户信息失败: %v", err)
	}

	// 7. 计算支付金额
	amount := upgradeRecord.UpgradeFee
	if user.Inside == 1 {
		amount = 0.01 // 内部用户测试金额
	}

	// 8. 创建订单记录
	order := model.Order{
		Id:              uuid.NewString(),
		OrderNo:         outTradeNo,
		UserId:          userID,
		ProductId:       "", // 升级订单没有产品ID
		PaymentPlatform: req.PayMethod,
		PaymentScene:    "app",
		Amount:          amount,
		Status:          "pending",
	}
	orderInsertResult, insertOrderErr := l.svcCtx.OrderModel.Insert(l.ctx, session, &order)
	if insertOrderErr != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建订单失败: %+v", insertOrderErr)
	}
	_ = orderInsertResult
	orderID := order.Id

	// 9. 更新升级记录的订单号
	upgradeRecord.OrderNo = lzUtils.StringToNullString(outTradeNo)
	if updateErr := l.svcCtx.AgentUpgradeModel.UpdateWithVersion(l.ctx, session, upgradeRecord); updateErr != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新升级记录订单号失败: %+v", updateErr)
	}

	// 10. 生成描述信息
	levelNames := map[int64]string{
		1: "普通代理",
		2: "黄金代理",
		3: "钻石代理",
	}
	fromLevelName := levelNames[upgradeRecord.FromLevel]
	toLevelName := levelNames[upgradeRecord.ToLevel]
	description := fmt.Sprintf("代理升级：%s → %s", fromLevelName, toLevelName)

	return &PaymentTypeResp{
		amount:      amount,
		outTradeNo:  outTradeNo,
		description: description,
		orderID:     orderID,
	}, nil
}

// getLevelBonus 获取等级加成（从配置表读取）
func (l *PaymentLogic) getLevelBonus(level int64) (int64, error) {
	var configKey string
	switch level {
	case 1: // 普通
		configKey = "level_1_bonus"
	case 2: // 黄金
		configKey = "level_2_bonus"
	case 3: // 钻石
		configKey = "level_3_bonus"
	default:
		return 0, nil
	}

	bonus, err := l.getConfigFloat(configKey)
	if err != nil {
		// 配置不存在时返回默认值
		l.Errorf("获取等级加成配置失败, level: %d, key: %s, err: %v，使用默认值", level, configKey, err)
		switch level {
		case 1:
			return 6, nil
		case 2:
			return 3, nil
		case 3:
			return 0, nil
		}
		return 0, nil
	}
	return int64(bonus), nil
}

// getConfigFloat 获取配置值（浮点数）
func (l *PaymentLogic) getConfigFloat(configKey string) (float64, error) {
	config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, configKey)
	if err != nil {
		return 0, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取配置失败, key: %s, %v", configKey, err)
	}
	value, err := strconv.ParseFloat(config.ConfigValue, 64)
	if err != nil {
		return 0, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解析配置值失败, key: %s, value: %s, %v", configKey, config.ConfigValue, err)
	}
	return value, nil
}
