package server

import (
	"encoding/json"

	"github.com/gorilla/websocket"
	"github.com/labstack/echo/v4"
)

var upgrader = websocket.Upgrader{}

type WebsocketHandler interface {
	Handle(message map[string]any, senderId string, sockets map[string]*websocket.Conn)
}

type WebsocketServer struct {
	router   *echo.Echo
	sockets  map[string]*websocket.Conn
	handlers []WebsocketHandler
}

func (s *WebsocketServer) Initialize(authenticator *Authenticator) {
	s.sockets = make(map[string]*websocket.Conn)
	s.router.Use(authenticator.Authenticate("/ws", []string{}))
	s.router.GET("/ws", s.handle)
}

func (s *WebsocketServer) handle(context echo.Context) error {
	authContext := context.(AuthContext)
	senderId := getAuthenticatedId(authContext)
	ws, err := upgrader.Upgrade(context.Response(), context.Request(), nil)
	s.sockets[senderId] = ws
	if err != nil {
		return err
	}
	defer func() {
		ws.Close()
		delete(s.sockets, senderId)
	}()

	for {
		messageType, messageBytes, err := ws.ReadMessage()
		if err != nil {
			return err
		}
		if messageType == websocket.TextMessage {
			var messageObject map[string]any
			json.Unmarshal(messageBytes, &messageObject)
			for _, handler := range s.handlers {
				handler.Handle(messageObject, senderId, s.sockets)
			}
		}
	}
}

func getAuthenticatedId(authContext AuthContext) string {
	if authContext.User != nil {
		return authContext.User.ID
	}
	if authContext.Integration != nil {
		return authContext.Integration.ID
	}
	return ""
}

func (s *WebsocketServer) AddHandler(handler WebsocketHandler) {
	s.handlers = append(s.handlers, handler)
}

func (s *WebsocketServer) SetRouter(router *echo.Echo) {
	s.router = router
}
