package logic

import (
	"encoding/json"
	"net/http"
	"time"
	"twitch-clone/chat-service/models"
	"twitch-clone/chat-service/repository"
	"twitch-clone/chat-service/serializer"

	"github.com/bwmarrin/snowflake"
	"github.com/olahol/melody"
)

type chatService struct {
	ChatRepo      repository.ChatRepository
	Melody        melody.Melody
	MsgSerializer serializer.JsonMessageSerializer
	Snowflake     snowflake.Node
}

func NewChatService(chatRepo repository.ChatRepository) *chatService {
	flakeGen, err := snowflake.NewNode(0)
	if err != nil {
		panic(err)
	}

	c := &chatService{
		ChatRepo:      chatRepo,
		Melody:        *melody.New(),
		MsgSerializer: serializer.JsonMessageSerializer{},
		Snowflake:     *flakeGen,
	}

	c.Melody.HandleMessage(func(s *melody.Session, b []byte) {
		msg, err := c.MsgSerializer.Decode(b)
		if err != nil {
			bytes, _ := json.Marshal(err.Error())
			s.Write(bytes)
			return
		}
		c.Publish(s.Request.URL.Path, msg)
	})

	return c
}

func (c *chatService) Subscribe(w http.ResponseWriter, r *http.Request) error {
	return c.Melody.HandleRequest(w, r)
}

func (c *chatService) Publish(namespace string, msg *models.ChatMessage) error {
	msg.MessageID = c.Snowflake.Generate().Int64()
	msg.CreatedAt = time.Now().Unix()

	rawMsg, err := c.MsgSerializer.Encode(msg)
	if err != nil {
		return err
	}

	err = c.Melody.BroadcastFilter(rawMsg, func(q *melody.Session) bool {
		return q.Request.URL.Path == namespace
	})
	if err != nil {
		return err
	}

	err = c.ChatRepo.Store(msg)
	return err
}