package user

import (
	"context"

	logicCommon "github.com/perfect-panel/server/internal/logic/common"
	"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 CancelWithdrawalLogic struct {
	logger.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewCancelWithdrawalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelWithdrawalLogic {
	return &CancelWithdrawalLogic{
		Logger: logger.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

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

	var withdrawal *user.Withdrawal
	err = l.svcCtx.DB.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error {
		var txErr error
		withdrawal, txErr = logicCommon.LoadPendingWithdrawalForUpdate(l.ctx, tx, req.WithdrawalId)
		if txErr != nil {
			if txErr.Error() == "withdrawal status invalid" {
				return errors.Wrapf(xerr.NewErrCode(xerr.WithdrawalStatusInvalid), "withdrawal %d is not in pending state", req.WithdrawalId)
			}
			return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "load withdrawal failed: %v", txErr)
		}

		if withdrawal.UserId != u.Id {
			return errors.Wrapf(xerr.NewErrCode(xerr.PermissionDenied), "user %d cannot cancel withdrawal belonging to user %d", u.Id, withdrawal.UserId)
		}

		if txErr = tx.Model(&user.Withdrawal{}).
			Where("id = ? AND status = ?", req.WithdrawalId, user.WithdrawalStatusPending).
			Update("status", user.WithdrawalStatusCancelled).Error; txErr != nil {
			return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "cancel withdrawal failed: %v", txErr)
		}

		// Commission was NOT deducted at application time under the HIF-22
		// approval flow, so cancellation requires no refund — only a status
		// update. Refunding here would mint phantom commission and pollute
		// reconciliation (mirrors rejectWithdrawal in admin/user/withdrawalCommon.go).

		return nil
	})
	if err != nil {
		return nil, err
	}

	_ = l.svcCtx.UserModel.ClearUserCache(l.ctx, u)

	return &types.WithdrawalLog{
		Id:        withdrawal.Id,
		UserId:    withdrawal.UserId,
		Amount:    withdrawal.Amount,
		Content:   withdrawal.Content,
		Status:    user.WithdrawalStatusCancelled,
		Reason:    "",
		Method:    withdrawal.Method,
		Account:   withdrawal.Account,
		QrCodeUrl: withdrawal.QrCodeUrl,
		CreatedAt: withdrawal.CreatedAt.UnixMilli(),
		UpdatedAt: withdrawal.UpdatedAt.UnixMilli(),
	}, nil
}
