package headscale

import (
	"io"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/rs/zerolog/log"
	"tailscale.com/tailcfg"
	"tailscale.com/types/wgkey"
)

func (h *Headscale) PollNetMapStream(
	c *gin.Context,
	m Machine,
	req tailcfg.MapRequest,
	mKey wgkey.Key,
	pollData chan []byte,
	update chan []byte,
	cancelKeepAlive chan []byte,
) {

	go h.keepAlive(cancelKeepAlive, pollData, mKey, req, m)

	c.Stream(func(w io.Writer) bool {
		log.Trace().
			Str("handler", "PollNetMapStream").
			Str("machine", m.Name).
			Msg("Waiting for data to stream...")
		select {

		case data := <-pollData:
			log.Trace().
				Str("handler", "PollNetMapStream").
				Str("machine", m.Name).
				Int("bytes", len(data)).
				Msg("Sending data received via pollData channel")
			_, err := w.Write(data)
			if err != nil {
				log.Error().
					Str("handler", "PollNetMapStream").
					Str("machine", m.Name).
					Err(err).
					Msg("Cannot write data")
			}
			log.Trace().
				Str("handler", "PollNetMapStream").
				Str("machine", m.Name).
				Int("bytes", len(data)).
				Msg("Data from pollData channel written successfully")
			now := time.Now().UTC()
			m.LastSeen = &now
			h.db.Save(&m)
			log.Trace().
				Str("handler", "PollNetMapStream").
				Str("machine", m.Name).
				Int("bytes", len(data)).
				Msg("Machine updated successfully after sending pollData")
			return true

		case <-update:
			log.Debug().
				Str("handler", "PollNetMapStream").
				Str("machine", m.Name).
				Msg("Received a request for update")
			data, err := h.getMapResponse(mKey, req, m)
			if err != nil {
				log.Error().
					Str("handler", "PollNetMapStream").
					Str("machine", m.Name).
					Err(err).
					Msg("Could not get the map update")
			}
			_, err = w.Write(*data)
			if err != nil {
				log.Error().
					Str("handler", "PollNetMapStream").
					Str("machine", m.Name).
					Err(err).
					Msg("Could not write the map response")
			}
			return true

		case <-c.Request.Context().Done():
			log.Info().
				Str("handler", "PollNetMapStream").
				Str("machine", m.Name).
				Msg("The client has closed the connection")
			now := time.Now().UTC()
			m.LastSeen = &now
			h.db.Save(&m)
			cancelKeepAlive <- []byte{}
			h.clientsPolling.Delete(m.ID)
			close(update)
			return false
		}
	})
}