// Package wallet 提供代理主钱包复杂写用例。
package wallet

import (
	"context"

	domainwallet "github.com/break/junhong_cmp_fiber/internal/domain/wallet"
	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"gorm.io/gorm"
)

// ChangeCreditService 调整既有店铺主钱包实际信用额度。
type ChangeCreditService struct {
	db *gorm.DB
}

// NewChangeCreditService 创建实际信用额度调整服务。
func NewChangeCreditService(db *gorm.DB) *ChangeCreditService {
	return &ChangeCreditService{db: db}
}

// Execute 按主钱包类型和版本条件更新，不修改余额、冻结金额或钱包流水。
func (s *ChangeCreditService) Execute(ctx context.Context, shopID uint, enabled bool, limit int64, version int) (*dto.ShopCreditLimitResponse, error) {
	var result *dto.ShopCreditLimitResponse
	err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		var stored model.AgentWallet
		if err := tx.Where("shop_id = ? AND wallet_type = ?", shopID, constants.AgentWalletTypeMain).First(&stored).Error; err != nil {
			return errors.New(errors.CodeWalletNotFound, "店铺主钱包不存在")
		}
		aggregate := domainwallet.AgentWallet{ID: stored.ID, ShopID: stored.ShopID, WalletType: stored.WalletType, Balance: stored.Balance, FrozenBalance: stored.FrozenBalance, CreditEnabled: stored.CreditEnabled, CreditLimit: stored.CreditLimit, Status: stored.Status, Version: stored.Version}
		if err := aggregate.ChangeCredit(enabled, limit); err != nil {
			return err
		}
		update := tx.Model(&model.AgentWallet{}).
			Where("id = ? AND wallet_type = ? AND version = ? AND balance::numeric - frozen_balance::numeric + ?::numeric >= 0", stored.ID, constants.AgentWalletTypeMain, version, aggregate.EffectiveCredit()).
			Updates(map[string]any{"credit_enabled": enabled, "credit_limit": limit, "version": gorm.Expr("version + 1")})
		if update.Error != nil {
			return errors.Wrap(errors.CodeInternalError, update.Error, "更新店铺信用额度失败")
		}
		if update.RowsAffected != 1 {
			var current model.AgentWallet
			if err := tx.Where("id = ? AND wallet_type = ?", stored.ID, constants.AgentWalletTypeMain).First(&current).Error; err != nil {
				return errors.New(errors.CodeWalletNotFound, "店铺主钱包不存在")
			}
			if current.Version != version {
				return errors.New(errors.CodeConflict, "钱包版本已变化，请刷新后重试")
			}
			return errors.New(errors.CodeInsufficientQuota, "当前资金占用无法降低或关闭信用额度")
		}
		available, _ := aggregate.AvailableBalance()
		result = &dto.ShopCreditLimitResponse{ShopID: shopID, WalletID: stored.ID, Balance: stored.Balance, FrozenBalance: stored.FrozenBalance, CreditEnabled: enabled, CreditLimit: limit, AvailableBalance: available, Version: version + 1}
		return nil
	})
	return result, err
}
