package postgres

import (
	"context"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

// AssetWalletStore 资产钱包数据访问层
type AssetWalletStore struct {
	db    *gorm.DB
	redis *redis.Client
}

// NewAssetWalletStore 创建资产钱包 Store
func NewAssetWalletStore(db *gorm.DB, redis *redis.Client) *AssetWalletStore {
	return &AssetWalletStore{
		db:    db,
		redis: redis,
	}
}

// GetByResourceTypeAndID 根据资源类型和 ID 查询钱包
func (s *AssetWalletStore) GetByResourceTypeAndID(ctx context.Context, resourceType string, resourceID uint) (*model.AssetWallet, error) {
	var wallet model.AssetWallet
	query := s.db.WithContext(ctx).
		Where("resource_type = ? AND resource_id = ?", resourceType, resourceID)
	// 应用数据权限过滤（使用 shop_id_tag 字段）
	query = middleware.ApplyShopTagFilter(ctx, query)
	err := query.First(&wallet).Error
	if err != nil {
		return nil, err
	}
	return &wallet, nil
}

// GetByID 根据钱包 ID 查询
func (s *AssetWalletStore) GetByID(ctx context.Context, id uint) (*model.AssetWallet, error) {
	var wallet model.AssetWallet
	query := s.db.WithContext(ctx).Where("id = ?", id)
	// 应用数据权限过滤（使用 shop_id_tag 字段）
	query = middleware.ApplyShopTagFilter(ctx, query)
	if err := query.First(&wallet).Error; err != nil {
		return nil, err
	}
	return &wallet, nil
}

// Create 创建资产钱包
func (s *AssetWalletStore) Create(ctx context.Context, wallet *model.AssetWallet) error {
	return s.db.WithContext(ctx).Create(wallet).Error
}

// CreateWithTx 创建资产钱包（带事务）
func (s *AssetWalletStore) CreateWithTx(ctx context.Context, tx *gorm.DB, wallet *model.AssetWallet) error {
	return tx.WithContext(ctx).Create(wallet).Error
}

// DeductBalanceWithTx 扣款（带事务，使用乐观锁）
func (s *AssetWalletStore) DeductBalanceWithTx(ctx context.Context, tx *gorm.DB, walletID uint, amount int64, version int) error {
	// 使用乐观锁，检查可用余额是否充足
	result := tx.WithContext(ctx).Model(&model.AssetWallet{}).
		Where("id = ? AND balance - frozen_balance >= ? AND version = ?", walletID, amount, version).
		Updates(map[string]interface{}{
			"balance":    gorm.Expr("balance - ?", amount),
			"version":    gorm.Expr("version + 1"),
			"updated_at": time.Now(),
		})

	if result.Error != nil {
		return result.Error
	}

	if result.RowsAffected == 0 {
		return gorm.ErrRecordNotFound
	}

	s.clearWalletCache(ctx, walletID)

	return nil
}

// AddBalanceWithTx 增加余额（带事务）
func (s *AssetWalletStore) AddBalanceWithTx(ctx context.Context, tx *gorm.DB, walletID uint, amount int64) error {
	result := tx.WithContext(ctx).Model(&model.AssetWallet{}).
		Where("id = ?", walletID).
		Updates(map[string]interface{}{
			"balance":    gorm.Expr("balance + ?", amount),
			"version":    gorm.Expr("version + 1"),
			"updated_at": time.Now(),
		})

	if result.Error != nil {
		return result.Error
	}

	if result.RowsAffected == 0 {
		return gorm.ErrRecordNotFound
	}

	s.clearWalletCache(ctx, walletID)

	return nil
}

// clearWalletCache 清除钱包缓存
func (s *AssetWalletStore) clearWalletCache(ctx context.Context, walletID uint) {
	var wallet model.AssetWallet
	if err := s.db.WithContext(ctx).Select("resource_type, resource_id").First(&wallet, walletID).Error; err != nil {
		return
	}

	cacheKey := constants.RedisAssetWalletBalanceKey(wallet.ResourceType, wallet.ResourceID)
	_ = s.redis.Del(ctx, cacheKey).Err()
}
