package localserver

import (
	"encoding/json"
	"fmt"
	"sync/atomic"
)

const (
	CHAT_MESSAGE_BROADCAST = "chat_message_broadcast"
	CHAT_MESSAGE_PRIVATE   = "chat_message_private"
)

type WebrtcCallChatManager struct{}

func NewWebrtcCallChatManager() *WebrtcCallChatManager {
	return new(WebrtcCallChatManager)
}

func (w *WebrtcCallChatManager) HandleCallEvent(from string, squadId string, eventId string, payload map[string]interface{}, data []byte, manager *WebRTCCallManager) (err error) {
	done, errCh := make(chan struct{}), make(chan error)
	go func() {
		logger.Println("got an event in call chat manager", from, eventId, payload)
		switch eventId {
		case CHAT_MESSAGE_BROADCAST:
			if e := validateEvent(payload, "message"); e != nil {
				errCh <- e
				return
			}
			if e := w.sendBrodcastChatMessage(from, payload["message"].(string), squadId, manager); e != nil {
				errCh <- e
				return
			}
		case CHAT_MESSAGE_PRIVATE:
			if e := validateEvent(payload, "message", "dst"); e != nil {
				errCh <- e
				return
			}
			if e := w.sendPrivateChatMessage(from, payload["message"].(string), squadId, manager, payload["message"].([]string)...); e != nil {
				errCh <- e
				return
			}
		}
		done <- struct{}{}
	}()
	select {
	case <-done:
		return nil
	case err = <-errCh:
		return
	}
}

func (w WebrtcCallChatManager) sendBrodcastChatMessage(from string, message string, squadId string, manager *WebRTCCallManager) (err error) {
	if _, ok := manager.Squads[squadId]; !ok {
		err = fmt.Errorf("no correponding squad found")
		return
	}
	for _, member := range manager.Squads[squadId].Members {
		if _, ok := manager.DataChannels[member]; ok && member != from {
			bs, marshalErr := json.Marshal(map[string]interface{}{
				"type": "send_chat_message",
				"from": from,
				"payload": map[string]string{
					"message": message,
				},
			})
			if marshalErr != nil {
				logger.Println(err)
				continue
			}
		lock:
			for {
				if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
					defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
					if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
						logger.Println(sendErr)
					}
					break lock
				} else {
					continue
				}
			}
		}
	}
	return
}

func (w WebrtcCallChatManager) sendPrivateChatMessage(from string, message string, squadId string, manager *WebRTCCallManager, dst ...string) (err error) {
	if _, ok := manager.Squads[squadId]; !ok {
		err = fmt.Errorf("no correponding squad found")
		return
	}
	for _, member := range manager.Squads[squadId].Members {
		for _, id := range dst {
			if id == member {
				if _, ok := manager.DataChannels[member]; ok && member != from {
					bs, marshalErr := json.Marshal(map[string]interface{}{
						"type": "",
						"from": from,
						"payload": map[string]string{
							"message": message,
						},
					})
					if marshalErr != nil {
						logger.Println(err)
						continue
					}
				lock:
					for {
						if atomic.CompareAndSwapUint32(manager.DataChannels[member].l, 0, 1) {
							defer atomic.SwapUint32(manager.DataChannels[member].l, 0)
							if sendErr := manager.DataChannels[member].DataChannel.SendText(string(bs)); sendErr != nil {
								logger.Println(sendErr)
							}
							break lock
						} else {
							continue
						}
					}
				}
			}
		}
	}
	return
}

func validateEvent(event map[string]interface{}, fields ...string) (err error) {
	for _, field := range fields {
		if _, ok := event[field]; !ok {
			err = fmt.Errorf("no field %s in req payload", field)
			return
		}
	}
	return
}
