package centrifugo

import (
	"context"
	"fmt"
	"time"
)

// OnlineStatus 在線狀態
type OnlineStatus struct {
	UserID     string    `json:"user_id"`
	IsOnline   bool      `json:"is_online"`
	LastSeenAt time.Time `json:"last_seen_at,omitempty"`
	Clients    int       `json:"clients,omitempty"` // 連線數（可能多個設備）
}

// OnlineStore 在線狀態存儲介面
// 可以用 Redis、Memory 或其他存儲實作
type OnlineStore interface {
	// SetOnline 設置用戶在線
	SetOnline(ctx context.Context, userID string, ttl time.Duration) error
	// SetOffline 設置用戶離線
	SetOffline(ctx context.Context, userID string) error
	// IsOnline 檢查用戶是否在線
	IsOnline(ctx context.Context, userID string) (bool, error)
	// GetOnlineUsers 獲取在線用戶列表
	GetOnlineUsers(ctx context.Context, userIDs []string) (map[string]bool, error)
	// IncrClient 增加用戶連線數
	IncrClient(ctx context.Context, userID string) (int64, error)
	// DecrClient 減少用戶連線數
	DecrClient(ctx context.Context, userID string) (int64, error)
}

// OnlineManager 在線狀態管理器
// 結合 Redis 存儲和 Centrifugo Presence API 提供在線狀態追蹤
type OnlineManager struct {
	client *Client
	store  OnlineStore
	ttl    time.Duration
}

// NewOnlineManager 創建在線狀態管理器
// store 可以為 nil，此時只使用 Centrifugo Presence API
func NewOnlineManager(client *Client, store OnlineStore) *OnlineManager {
	return &OnlineManager{
		client: client,
		store:  store,
		ttl:    5 * time.Minute, // 預設 5 分鐘過期
	}
}

// NewOnlineManagerWithTTL 創建帶 TTL 的在線狀態管理器
func NewOnlineManagerWithTTL(client *Client, store OnlineStore, ttl time.Duration) *OnlineManager {
	return &OnlineManager{
		client: client,
		store:  store,
		ttl:    ttl,
	}
}

// ==================== 連線事件處理 ====================

// HandleConnect 處理用戶連線事件（用於 Centrifugo Connect Proxy）
func (m *OnlineManager) HandleConnect(ctx context.Context, userID string) error {
	if m.store == nil {
		return nil
	}

	// 增加連線數
	count, err := m.store.IncrClient(ctx, userID)
	if err != nil {
		return fmt.Errorf("failed to incr client: %w", err)
	}

	// 如果是第一個連線，設置在線狀態
	if count == 1 {
		if err := m.store.SetOnline(ctx, userID, m.ttl); err != nil {
			return fmt.Errorf("failed to set online: %w", err)
		}
	}

	return nil
}

// HandleDisconnect 處理用戶斷線事件（用於 Centrifugo Disconnect Proxy）
func (m *OnlineManager) HandleDisconnect(ctx context.Context, userID string) error {
	if m.store == nil {
		return nil
	}

	// 減少連線數
	count, err := m.store.DecrClient(ctx, userID)
	if err != nil {
		return fmt.Errorf("failed to decr client: %w", err)
	}

	// 如果沒有連線了，設置離線狀態
	if count <= 0 {
		if err := m.store.SetOffline(ctx, userID); err != nil {
			return fmt.Errorf("failed to set offline: %w", err)
		}
	}

	return nil
}

// ==================== 在線狀態查詢 ====================

// IsUserOnline 檢查用戶是否在線（使用 Store）
func (m *OnlineManager) IsUserOnline(ctx context.Context, userID string) (bool, error) {
	if m.store == nil {
		return false, ErrOnlineStoreNotConfigured
	}
	return m.store.IsOnline(ctx, userID)
}

// GetUsersOnlineStatus 批量獲取用戶在線狀態
func (m *OnlineManager) GetUsersOnlineStatus(ctx context.Context, userIDs []string) (map[string]bool, error) {
	if m.store == nil {
		return nil, ErrOnlineStoreNotConfigured
	}
	return m.store.GetOnlineUsers(ctx, userIDs)
}

// RefreshOnline 刷新用戶在線狀態（用於心跳）
func (m *OnlineManager) RefreshOnline(ctx context.Context, userID string) error {
	if m.store == nil {
		return nil
	}
	return m.store.SetOnline(ctx, userID, m.ttl)
}

// ==================== Centrifugo Presence API ====================

// IsUserInChannel 檢查用戶是否在指定頻道中（使用 Centrifugo Presence）
func (m *OnlineManager) IsUserInChannel(ctx context.Context, userID, channel string) (bool, error) {
	presence, err := m.client.Presence(ctx, channel)
	if err != nil {
		return false, err
	}

	for _, info := range presence.Presence {
		if info.User == userID {
			return true, nil
		}
	}

	return false, nil
}

// GetChannelOnlineUsers 獲取頻道中的在線用戶（使用 Centrifugo Presence）
func (m *OnlineManager) GetChannelOnlineUsers(ctx context.Context, channel string) ([]string, error) {
	presence, err := m.client.Presence(ctx, channel)
	if err != nil {
		return nil, err
	}

	// 去重（一個用戶可能有多個連線）
	userMap := make(map[string]bool)
	for _, info := range presence.Presence {
		userMap[info.User] = true
	}

	users := make([]string, 0, len(userMap))
	for userID := range userMap {
		users = append(users, userID)
	}

	return users, nil
}

// GetChannelStats 獲取頻道在線統計
func (m *OnlineManager) GetChannelStats(ctx context.Context, channel string) (*PresenceStatsResult, error) {
	return m.client.PresenceStats(ctx, channel)
}
