package user

import (
	"context"

	"github.com/perfect-panel/server/internal/model/user"
	"github.com/perfect-panel/server/internal/svc"
	"github.com/perfect-panel/server/internal/types"
	"github.com/perfect-panel/server/pkg/constant"
	"github.com/perfect-panel/server/pkg/logger"
	"github.com/perfect-panel/server/pkg/xerr"
	"github.com/pkg/errors"
	"gorm.io/gorm"
)

type CommissionWithdrawLogic struct {
	logger.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// Commission Withdraw
func NewCommissionWithdrawLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CommissionWithdrawLogic {
	return &CommissionWithdrawLogic{
		Logger: logger.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *CommissionWithdrawLogic) CommissionWithdraw(req *types.CommissionWithdrawRequest) (resp *types.WithdrawalLog, err error) {
	u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User)
	if !ok {
		logger.Error("current user is not found in context")
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
	}

	// Sum all pending (status=0) withdrawals to compute available balance.
	// Available = commission - pendingTotal; commission is only deducted on approval.
	var pendingTotal int64
	if err = l.svcCtx.DB.WithContext(l.ctx).
		Model(&user.Withdrawal{}).
		Where("user_id = ? AND status = 0", u.Id).
		Select("COALESCE(SUM(amount), 0)").
		Scan(&pendingTotal).Error; err != nil {
		l.Errorf("Failed to query pending withdrawals for user %d: %v", u.Id, err)
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Failed to query pending withdrawals for user %d", u.Id)
	}

	if u.Commission < req.Amount+pendingTotal {
		logger.Errorf("User %d insufficient available commission: total=%d pending=%d requested=%d",
			u.Id, u.Commission, pendingTotal, req.Amount)
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserCommissionNotEnough), "User %d has insufficient commission balance", u.Id)
	}

	var w user.Withdrawal
	err = l.svcCtx.DB.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error {
		w = user.Withdrawal{
			UserId:  u.Id,
			Amount:  req.Amount,
			Content: req.Content,
			Status:  0,
			Reason:  "",
		}
		return tx.Create(&w).Error
	})
	if err != nil {
		l.Errorf("Failed to create withdrawal for user %d: %v", u.Id, err)
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "Failed to create withdrawal for user %d: %v", u.Id, err)
	}

	return &types.WithdrawalLog{
		UserId:    u.Id,
		Amount:    req.Amount,
		Content:   req.Content,
		Status:    0,
		Reason:    "",
		CreatedAt: w.CreatedAt.UnixMilli(),
		UpdatedAt: w.UpdatedAt.UnixMilli(),
	}, nil
}
