package websocket

import (
	"time"
)

// Broadcaster mengelola broadcasting pesan
type Broadcaster struct {
	hub *Hub
}

// NewBroadcaster membuat broadcaster baru
func NewBroadcaster(hub *Hub) *Broadcaster {
	return &Broadcaster{hub: hub}
}

// StartServerBroadcasters memulai broadcaster server
func (b *Broadcaster) StartServerBroadcasters() {
	// Heartbeat broadcaster
	go b.startHeartbeatBroadcaster()

	// System notification broadcaster
	go b.startSystemNotificationBroadcaster()

	// Data stream broadcaster
	go b.startDataStreamBroadcaster()
}

// startHeartbeatBroadcaster memulai broadcaster heartbeat
func (b *Broadcaster) startHeartbeatBroadcaster() {
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			b.hub.mu.RLock()
			connectedClients := len(b.hub.clients)
			uniqueIPs := len(b.hub.clientsByIP)
			staticClients := len(b.hub.clientsByStatic)
			b.hub.mu.RUnlock()

			b.BroadcastMessage("server_heartbeat", map[string]interface{}{
				"message":           "Server heartbeat",
				"connected_clients": connectedClients,
				"unique_ips":        uniqueIPs,
				"static_clients":    staticClients,
				"timestamp":         time.Now().Unix(),
				"server_id":         b.hub.config.ServerID,
			})
		case <-b.hub.ctx.Done():
			return
		}
	}
}

// startSystemNotificationBroadcaster memulai broadcaster notifikasi sistem
func (b *Broadcaster) startSystemNotificationBroadcaster() {
	ticker := time.NewTicker(5 * time.Minute)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			dbHealth := b.hub.dbService.Health()
			b.BroadcastMessage("system_status", map[string]interface{}{
				"type":      "system_notification",
				"database":  dbHealth,
				"timestamp": time.Now().Unix(),
				"uptime":    time.Since(b.hub.startTime).String(),
			})
		case <-b.hub.ctx.Done():
			return
		}
	}
}

// startDataStreamBroadcaster memulai broadcaster aliran data
func (b *Broadcaster) startDataStreamBroadcaster() {
	ticker := time.NewTicker(10 * time.Second)
	defer ticker.Stop()
	counter := 0

	for {
		select {
		case <-ticker.C:
			counter++
			b.BroadcastMessage("data_stream", map[string]interface{}{
				"id":        counter,
				"value":     counter * 10,
				"timestamp": time.Now().Unix(),
				"type":      "real_time_data",
			})
		case <-b.hub.ctx.Done():
			return
		}
	}
}

// BroadcastMessage mengirim pesan ke semua klien
func (b *Broadcaster) BroadcastMessage(messageType string, data interface{}) {
	msg := NewWebSocketMessage(MessageType(messageType), data, "", "")

	select {
	case b.hub.messageQueue <- msg:
	default:
		// Antrian penuh, abaikan pesan
	}
}

// BroadcastToRoom mengirim pesan ke ruangan tertentu
func (b *Broadcaster) BroadcastToRoom(room string, messageType string, data interface{}) {
	msg := NewWebSocketMessage(
		MessageType(messageType),
		map[string]interface{}{
			"room": room,
			"data": data,
		},
		"",
		room,
	)

	select {
	case b.hub.messageQueue <- msg:
	default:
		// Antrian penuh, abaikan pesan
	}
}

// SendToClient mengirim pesan ke klien tertentu
func (b *Broadcaster) SendToClient(clientID string, messageType string, data interface{}) {
	msg := NewWebSocketMessage(MessageType(messageType), data, clientID, "")

	select {
	case b.hub.messageQueue <- msg:
	default:
		// Antrian penuh, abaikan pesan
	}
}

// SendToClientByStaticID mengirim pesan ke klien berdasarkan ID statis
func (b *Broadcaster) SendToClientByStaticID(staticID string, messageType string, data interface{}) bool {
	b.hub.mu.RLock()
	client, exists := b.hub.clientsByStatic[staticID]
	b.hub.mu.RUnlock()

	if !exists {
		return false
	}

	b.SendToClient(client.ID, messageType, data)
	return true
}

// BroadcastToIP mengirim pesan ke semua klien dari IP tertentu
func (b *Broadcaster) BroadcastToIP(ipAddress string, messageType string, data interface{}) int {
	b.hub.mu.RLock()
	clients := b.hub.clientsByIP[ipAddress]
	b.hub.mu.RUnlock()

	count := 0
	for _, client := range clients {
		b.SendToClient(client.ID, messageType, data)
		count++
	}

	return count
}

// BroadcastClientToClient mengirim pesan dari satu klien ke klien lain
func (b *Broadcaster) BroadcastClientToClient(fromClientID, toClientID string, messageType string, data interface{}) {
	message := NewWebSocketMessage(MessageType(messageType), map[string]interface{}{
		"from_client_id": fromClientID,
		"data":           data,
	}, toClientID, "")
	b.hub.broadcast <- message
}

// BroadcastServerToClient mengirim pesan dari server ke klien tertentu
func (b *Broadcaster) BroadcastServerToClient(clientID string, messageType string, data interface{}) {
	message := NewWebSocketMessage(MessageType(messageType), data, clientID, "")
	b.hub.broadcast <- message
}

// BroadcastServerToRoom mengirim pesan dari server ke ruangan tertentu
func (b *Broadcaster) BroadcastServerToRoom(room string, messageType string, data interface{}) {
	message := NewWebSocketMessage(MessageType(messageType), data, "", room)
	b.hub.broadcast <- message
}

// BroadcastServerToAll mengirim pesan dari server ke semua klien
func (b *Broadcaster) BroadcastServerToAll(messageType string, data interface{}) {
	message := NewWebSocketMessage(MessageType(messageType), data, "", "")
	b.hub.broadcast <- message
}
