package centrifugo

import (
	"context"
	"fmt"
	"strconv"
	"time"

	"github.com/zeromicro/go-zero/core/stores/redis"
)

// RedisOnlineStore 使用 Redis 實作的在線狀態存儲
type RedisOnlineStore struct {
	client    *redis.Redis
	keyPrefix string
}

// NewRedisOnlineStore 創建 Redis 在線狀態存儲
func NewRedisOnlineStore(client *redis.Redis) *RedisOnlineStore {
	return &RedisOnlineStore{
		client:    client,
		keyPrefix: "online:",
	}
}

// NewRedisOnlineStoreWithPrefix 創建帶自定義前綴的 Redis 在線狀態存儲
func NewRedisOnlineStoreWithPrefix(client *redis.Redis, prefix string) *RedisOnlineStore {
	return &RedisOnlineStore{
		client:    client,
		keyPrefix: prefix,
	}
}

// key 生成 Redis key
func (s *RedisOnlineStore) key(userID string) string {
	return s.keyPrefix + userID
}

// clientCountKey 生成連線數 key
func (s *RedisOnlineStore) clientCountKey(userID string) string {
	return s.keyPrefix + "clients:" + userID
}

// SetOnline 設置用戶在線
func (s *RedisOnlineStore) SetOnline(ctx context.Context, userID string, ttl time.Duration) error {
	return s.client.SetexCtx(ctx, s.key(userID), fmt.Sprintf("%d", time.Now().Unix()), int(ttl.Seconds()))
}

// SetOffline 設置用戶離線
func (s *RedisOnlineStore) SetOffline(ctx context.Context, userID string) error {
	// 刪除在線狀態
	_, err := s.client.DelCtx(ctx, s.key(userID))
	if err != nil {
		return err
	}
	// 刪除連線數
	_, err = s.client.DelCtx(ctx, s.clientCountKey(userID))
	return err
}

// IsOnline 檢查用戶是否在線
func (s *RedisOnlineStore) IsOnline(ctx context.Context, userID string) (bool, error) {
	return s.client.ExistsCtx(ctx, s.key(userID))
}

// GetOnlineUsers 批量獲取在線用戶狀態
func (s *RedisOnlineStore) GetOnlineUsers(ctx context.Context, userIDs []string) (map[string]bool, error) {
	if len(userIDs) == 0 {
		return make(map[string]bool), nil
	}

	result := make(map[string]bool, len(userIDs))
	for _, userID := range userIDs {
		exists, err := s.client.ExistsCtx(ctx, s.key(userID))
		if err != nil {
			return nil, fmt.Errorf("failed to check online status for %s: %w", userID, err)
		}
		result[userID] = exists
	}

	return result, nil
}

// IncrClient 增加用戶連線數
func (s *RedisOnlineStore) IncrClient(ctx context.Context, userID string) (int64, error) {
	count, err := s.client.IncrCtx(ctx, s.clientCountKey(userID))
	if err != nil {
		return 0, err
	}
	return int64(count), nil
}

// DecrClient 減少用戶連線數
func (s *RedisOnlineStore) DecrClient(ctx context.Context, userID string) (int64, error) {
	count, err := s.client.DecrCtx(ctx, s.clientCountKey(userID))
	if err != nil {
		return 0, err
	}

	// 確保不會變成負數
	if count < 0 {
		_ = s.client.SetCtx(ctx, s.clientCountKey(userID), "0")
		return 0, nil
	}

	return int64(count), nil
}

// GetClientCount 獲取用戶連線數
func (s *RedisOnlineStore) GetClientCount(ctx context.Context, userID string) (int64, error) {
	val, err := s.client.GetCtx(ctx, s.clientCountKey(userID))
	if err != nil {
		return 0, err
	}
	if val == "" {
		return 0, nil
	}
	return strconv.ParseInt(val, 10, 64)
}

// GetAllOnlineUserIDs 獲取所有在線用戶 ID
// 注意：此方法使用 KEYS 命令，在大規模生產環境中可能有性能問題
// 建議在需要時使用 Centrifugo Presence API 替代
func (s *RedisOnlineStore) GetAllOnlineUserIDs(ctx context.Context) ([]string, error) {
	// 使用 KEYS 查找所有在線用戶（排除 clients: 開頭的 key）
	pattern := s.keyPrefix + "[^c]*"
	keys, err := s.client.KeysCtx(ctx, pattern)
	if err != nil {
		return nil, err
	}

	userIDs := make([]string, 0, len(keys))
	prefixLen := len(s.keyPrefix)
	for _, key := range keys {
		if len(key) > prefixLen {
			userIDs = append(userIDs, key[prefixLen:])
		}
	}

	return userIDs, nil
}
