/*
Copyright © 2024 filifa

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cmd

import (
	"net/url"
	"strconv"
	"time"

	"github.com/gorilla/websocket"
)

// Push is a struct for holding data sent to us through the websocket that we
// care about.
type push struct {
	UpdateId string
}

const (
	GameFinalCode       = 4200
	GameUnavailableCode = 4400
)

// GamedayWebsocket is a struct for establishing a websocket connection with
// the Stats API.
type gamedayWebsocket struct {
	baseURL url.URL
	*websocket.Conn
}

// NewGamedayWebsocket creates a statsapi.GamedayWebsocket using the Stats API
// websocket URL and establishes a connection.
func newGamedayWebsocket(gamePk int32) (*gamedayWebsocket, error) {
	ws := gamedayWebsocket{
		baseURL: url.URL{
			Scheme: "wss",
			Host:   "ws.statsapi.mlb.com",
		},
	}

	err := ws.init(gamePk)
	return &ws, err
}

func (g *gamedayWebsocket) init(gamePk int32) error {
	endpoint := url.URL{
		Path: "api/v1/game/push/subscribe/gameday/" + strconv.Itoa(int(gamePk)),
	}

	url := g.baseURL.ResolveReference(&endpoint)
	conn, _, err := websocket.DefaultDialer.Dial(url.String(), nil)

	g.Conn = conn
	return err
}

// SendKeepAlive sends the keep-alive message observed to be sent by MLB
// Gameday ("Gameday5").
func (g *gamedayWebsocket) sendKeepAlive() error {
	msg := []byte("Gameday5")
	err := g.Conn.WriteMessage(websocket.TextMessage, msg)
	return err
}

// KeepAlive sends the keep-alive message on a certain interval and sends any
// errors to ch.
func (g *gamedayWebsocket) keepAlive(interval time.Duration, ch chan<- error) {
	ticker := time.NewTicker(interval)
	defer ticker.Stop()

	for range ticker.C {
		err := g.sendKeepAlive()
		if err != nil {
			ch <- err
		}
	}
}
