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"
)

// AgentWalletStore 代理钱包数据访问层
type AgentWalletStore struct {
	db    *gorm.DB
	redis *redis.Client
}

// NewAgentWalletStore 创建代理钱包 Store
func NewAgentWalletStore(db *gorm.DB, redis *redis.Client) *AgentWalletStore {
	return &AgentWalletStore{
		db:    db,
		redis: redis,
	}
}

// GetCommissionWallet 获取店铺的分佣钱包
func (s *AgentWalletStore) GetCommissionWallet(ctx context.Context, shopID uint) (*model.AgentWallet, error) {
	return s.GetByShopIDAndType(ctx, shopID, constants.AgentWalletTypeCommission)
}

// GetMainWallet 获取店铺的主钱包
func (s *AgentWalletStore) GetMainWallet(ctx context.Context, shopID uint) (*model.AgentWallet, error) {
	return s.GetByShopIDAndType(ctx, shopID, constants.AgentWalletTypeMain)
}

// GetByShopIDAndType 根据店铺 ID 和钱包类型查询钱包
func (s *AgentWalletStore) GetByShopIDAndType(ctx context.Context, shopID uint, walletType string) (*model.AgentWallet, error) {
	// 尝试从缓存获取
	cacheKey := constants.RedisAgentWalletBalanceKey(shopID, walletType)
	// 注意：这里简化处理，实际项目中可以缓存完整的钱包信息

	var wallet model.AgentWallet
	query := s.db.WithContext(ctx).
		Where("shop_id = ? AND wallet_type = ?", shopID, walletType)
	// 应用数据权限过滤
	query = middleware.ApplyShopFilter(ctx, query)
	err := query.First(&wallet).Error
	if err != nil {
		return nil, err
	}

	// 更新缓存（可选）
	// 这里简化处理，不缓存完整对象
	_ = cacheKey

	return &wallet, nil
}

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

// Create 创建代理钱包
func (s *AgentWalletStore) Create(ctx context.Context, wallet *model.AgentWallet) error {
	return s.db.WithContext(ctx).Create(wallet).Error
}

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

// DeductFrozenBalanceWithTx 从分佣钱包冻结余额扣款（带事务）。
// 代理主钱包必须使用 Wallet Application，禁止通过旧 Store 写接缝变更。
func (s *AgentWalletStore) DeductFrozenBalanceWithTx(ctx context.Context, tx *gorm.DB, walletID uint, amount int64) error {
	// 扣除冻结余额和总余额
	result := tx.WithContext(ctx).Model(&model.AgentWallet{}).
		Where("id = ? AND wallet_type = ? AND frozen_balance >= ?", walletID, constants.AgentWalletTypeCommission, amount).
		Updates(map[string]interface{}{
			"balance":        gorm.Expr("balance - ?", amount),
			"frozen_balance": gorm.Expr("frozen_balance - ?", amount),
			"updated_at":     time.Now(),
		})

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

	if result.RowsAffected == 0 {
		return gorm.ErrRecordNotFound // 冻结余额不足
	}

	// 删除缓存
	s.clearWalletCache(ctx, walletID)

	return nil
}

// UnfreezeBalanceWithTx 解冻分佣钱包余额（带事务）。
// 代理主钱包必须使用 Wallet Application，禁止通过旧 Store 写接缝变更。
func (s *AgentWalletStore) UnfreezeBalanceWithTx(ctx context.Context, tx *gorm.DB, walletID uint, amount int64) error {
	// 减少冻结余额（总余额不变）
	result := tx.WithContext(ctx).Model(&model.AgentWallet{}).
		Where("id = ? AND wallet_type = ? AND frozen_balance >= ?", walletID, constants.AgentWalletTypeCommission, amount).
		Updates(map[string]interface{}{
			"frozen_balance": gorm.Expr("frozen_balance - ?", amount),
			"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 增加分佣钱包余额（带事务）。
// 代理主钱包充值、退款和人工调整必须使用 Wallet Application。
func (s *AgentWalletStore) AddBalanceWithTx(ctx context.Context, tx *gorm.DB, walletID uint, amount int64) error {
	result := tx.WithContext(ctx).Model(&model.AgentWallet{}).
		Where("id = ? AND wallet_type = ?", walletID, constants.AgentWalletTypeCommission).
		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
}

// GetShopCommissionSummaryBatch 批量获取店铺佣金钱包汇总
// 返回 map[shopID]*AgentWallet
func (s *AgentWalletStore) GetShopCommissionSummaryBatch(ctx context.Context, shopIDs []uint) (map[uint]*model.AgentWallet, error) {
	if len(shopIDs) == 0 {
		return make(map[uint]*model.AgentWallet), nil
	}

	var wallets []model.AgentWallet
	query := s.db.WithContext(ctx).
		Where("shop_id IN ? AND wallet_type = ?", shopIDs, constants.AgentWalletTypeCommission)
	// 应用数据权限过滤
	query = middleware.ApplyShopFilter(ctx, query)
	err := query.Find(&wallets).Error
	if err != nil {
		return nil, err
	}

	// 转换为 map
	result := make(map[uint]*model.AgentWallet, len(wallets))
	for i := range wallets {
		result[wallets[i].ShopID] = &wallets[i]
	}

	return result, nil
}

// GetShopMainWalletBatch 批量获取店铺主钱包（预充值钱包）
// 返回 map[shopID]*AgentWallet，未找到的店铺不会出现在结果中
func (s *AgentWalletStore) GetShopMainWalletBatch(ctx context.Context, shopIDs []uint) (map[uint]*model.AgentWallet, error) {
	if len(shopIDs) == 0 {
		return make(map[uint]*model.AgentWallet), nil
	}

	var wallets []model.AgentWallet
	query := s.db.WithContext(ctx).
		Where("shop_id IN ? AND wallet_type = ?", shopIDs, constants.AgentWalletTypeMain)
	// 对齐 GetShopCommissionSummaryBatch 的防御式过滤
	query = middleware.ApplyShopFilter(ctx, query)
	err := query.Find(&wallets).Error
	if err != nil {
		return nil, err
	}

	result := make(map[uint]*model.AgentWallet, len(wallets))
	for i := range wallets {
		result[wallets[i].ShopID] = &wallets[i]
	}

	return result, nil
}

// clearWalletCache 清除钱包缓存
func (s *AgentWalletStore) clearWalletCache(ctx context.Context, walletID uint) {
	// 查询钱包信息以获取 shop_id 和 wallet_type
	var wallet model.AgentWallet
	if err := s.db.WithContext(ctx).Select("shop_id, wallet_type").First(&wallet, walletID).Error; err != nil {
		return
	}

	cacheKey := constants.RedisAgentWalletBalanceKey(wallet.ShopID, wallet.WalletType)
	_ = s.redis.Del(ctx, cacheKey).Err()
}
