// Package messagehook contains actors to send discord / slack webhook
// requests
package messagehook

import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"net/http"
	"time"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"

	"github.com/Luzifer/twitch-bot/v3/plugins"
)

const (
	postTimeout = 5 * time.Second
)

var formatMessage plugins.MsgFormatter

// Register provides the plugins.RegisterFunc
func Register(args plugins.RegistrationArguments) error {
	formatMessage = args.FormatMessage

	discordActor{}.register(args)
	slackCompatibleActor{}.register(args)

	return nil
}

func sendPayload(hookURL string, payload any, expRespCode int) (preventCooldown bool, err error) {
	body := new(bytes.Buffer)
	if err = json.NewEncoder(body).Encode(payload); err != nil {
		return false, errors.Wrap(err, "marshalling payload")
	}

	logrus.WithField("payload", body.String()).Trace("sending webhook payload")

	ctx, cancel := context.WithTimeout(context.Background(), postTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, hookURL, body)
	if err != nil {
		return false, errors.Wrap(err, "creating request")
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return false, errors.Wrap(err, "executing request")
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			logrus.WithError(err).Error("closing response body (leaked fd)")
		}
	}()

	if resp.StatusCode != expRespCode {
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			body = []byte(errors.Wrap(err, "reading body").Error())
		}
		return false, errors.Errorf("unexpected response code %d (Body: %s)", resp.StatusCode, body)
	}

	return false, nil
}