package withdrawal

import (
	"context"
	"errors"

	"hfb_sys/backend/internal/model"
	"hfb_sys/backend/internal/modules/wallet"

	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

// 用户创建提现申请
func (r *Repository) Create(ctx context.Context, userID uint64, req CreateWithdrawalRequest) (*WithdrawalDTO, error) {
	db := r.db.WithContext(ctx)
	// 验证收款账号
	var paymentAccount model.UserPaymentAccount
	if err := db.Where("id = ? AND user_id = ? AND status = ?", req.PaymentAccountID, userID, "active").
		First(&paymentAccount).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("payment account not found")
		}
		return nil, err
	}

	// 计算手续费和实际到账金额（分）
	feeCent := int64(float64(req.AmountCent) * WithdrawalFeeRate)
	actualAmountCent := req.AmountCent - feeCent

	// 生成提现单号
	withdrawNo, err := generateWithdrawNo()
	if err != nil {
		return nil, err
	}

	// 解密账号（用于存储快照）
	decryptedNo, err := r.decryptAccountNo(paymentAccount.AccountNo)
	if err != nil {
		decryptedNo = paymentAccount.AccountNo
	}

	withdrawal := model.WithdrawalRequest{
		WithdrawNo:       withdrawNo,
		UserID:           userID,
		AmountCent:       req.AmountCent,
		FeeCent:          feeCent,
		ActualAmountCent: actualAmountCent,
		PaymentAccountID: &req.PaymentAccountID,
		AccountType:      paymentAccount.AccountType,
		AccountName:      paymentAccount.AccountName,
		AccountNo:        maskAccountNo(decryptedNo, paymentAccount.AccountType),
		BankName:         paymentAccount.BankName,
		BankBranch:       paymentAccount.BankBranch,
		Status:           "pending",
	}

	// 事务处理
	err = db.Transaction(func(tx *gorm.DB) error {
		// 创建提现申请
		if err := tx.Create(&withdrawal).Error; err != nil {
			return err
		}

		// 冻结用户余额
		if err := wallet.AppendEntries(tx, wallet.Entry{
			UserID:      userID,
			Direction:   "out",
			AmountCent:  req.AmountCent,
			BalanceType: "available",
			BizType:     "withdraw_freeze",
			BizNo:       withdrawNo,
			Remark:      "提现冻结",
		}, wallet.Entry{
			UserID:      userID,
			Direction:   "in",
			AmountCent:  req.AmountCent,
			BalanceType: "frozen",
			BizType:     "withdraw_freeze",
			BizNo:       withdrawNo,
			Remark:      "提现冻结",
		}); err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return r.FindByID(ctx, userID, withdrawal.ID)
}

// 用户查询提现列表

// 用户查询提现列表
func (r *Repository) List(ctx context.Context, userID uint64, page, pageSize int) (*PaginatedResult, error) {
	db := r.db.WithContext(ctx)
	var total int64
	if err := db.Model(&model.WithdrawalRequest{}).
		Where("user_id = ?", userID).
		Count(&total).Error; err != nil {
		return nil, err
	}

	offset := (page - 1) * pageSize
	var withdrawals []model.WithdrawalRequest
	if err := db.Where("user_id = ?", userID).
		Order("created_at DESC").
		Offset(offset).Limit(pageSize).
		Find(&withdrawals).Error; err != nil {
		return nil, err
	}

	items := make([]WithdrawalDTO, 0, len(withdrawals))
	for _, w := range withdrawals {
		items = append(items, toDTO(w))
	}

	return &PaginatedResult{
		Items:    items,
		Total:    total,
		Page:     page,
		PageSize: pageSize,
	}, nil
}

// 用户查询提现详情

// 用户查询提现详情
func (r *Repository) FindByID(ctx context.Context, userID, id uint64) (*WithdrawalDTO, error) {
	var withdrawal model.WithdrawalRequest
	if err := r.db.WithContext(ctx).Where("id = ? AND user_id = ?", id, userID).
		First(&withdrawal).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, ErrWithdrawalNotFound
		}
		return nil, err
	}
	dto := toDTO(withdrawal)
	return &dto, nil
}

// 用户取消提现

// 用户取消提现
func (r *Repository) Cancel(ctx context.Context, userID, id uint64) error {
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		var withdrawal model.WithdrawalRequest
		if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
			Where("id = ? AND user_id = ?", id, userID).
			First(&withdrawal).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return ErrWithdrawalNotFound
			}
			return err
		}

		// 事务内加行锁后重新校验，只有待审核状态可以取消，避免与管理员审核并发重复解冻
		if withdrawal.Status != "pending" {
			return ErrWithdrawalLocked
		}

		// 更新状态
		if err := tx.Model(&withdrawal).Update("status", "cancelled").Error; err != nil {
			return err
		}

		// 解冻余额
		if err := wallet.AppendEntries(tx, wallet.Entry{
			UserID:      userID,
			Direction:   "out",
			AmountCent:  withdrawal.AmountCent,
			BalanceType: "frozen",
			BizType:     "withdraw_cancel",
			BizNo:       withdrawal.WithdrawNo,
			Remark:      "用户取消提现",
		}, wallet.Entry{
			UserID:      userID,
			Direction:   "in",
			AmountCent:  withdrawal.AmountCent,
			BalanceType: "available",
			BizType:     "withdraw_cancel",
			BizNo:       withdrawal.WithdrawNo,
			Remark:      "用户取消提现",
		}); err != nil {
			return err
		}

		return nil
	})
}

// 管理员查询提现列表
