// Package slack provides functionality to send slack notifications
package slack

import (
	"fmt"
	"sync"
	"time"

	"quantex.com/qfixpt/src/app/version"
	common "quantex.com/qfixpt/src/client/notify"
	"quantex.com/qfixpt/src/common/logger"
	"quantex.com/qfixpt/src/common/tracerr"
	"quantex.com/qfixpt/src/domain"
)

type ChannelKey string

const slackBotURL = "https://hooks.slack.com/services/"

type Notify struct {
	channels map[domain.MessageChannel]ChannelKey
}

func New(chls domain.Channels) *Notify {
	if err := common.ValidateChannelConfig(chls); err != nil {
		panic(tracerr.Errorf("slack config error: %w", err))
	}

	channels := make(map[domain.MessageChannel]ChannelKey)

	channels[domain.MessageChannelTest] = ChannelKey(chls.Test)
	channels[domain.MessageChannelWeb] = ChannelKey(chls.Web)
	channels[domain.MessageChannelPanic] = ChannelKey(chls.Panic)
	channels[domain.MessageChannelError] = ChannelKey(chls.Error)

	return &Notify{
		channels: channels,
	}
}

func (s *Notify) Example() {
	wg := sync.WaitGroup{}
	wg.Add(1)
	s.SendMsg(domain.MessageChannelTest, "Hello World!", domain.MessageStatusGood, &wg)
	wg.Wait()
}

func (s *Notify) SendMsg(channel domain.MessageChannel, text string, status domain.MessageStatus, waitgroup *sync.WaitGroup) {
	var chKey ChannelKey

	if c, ok := s.channels[channel]; !ok {
		chKey = s.channels[domain.MessageChannelError]

		err := tracerr.Errorf("error sending slack notification, there's no channel key for channel: %s", channel)

		logger.ErrorWoNotifier("%v", err.Error())
	} else {
		chKey = c
	}

	common.SendWithRetry(text, status, waitgroup, slackBotURL+string(chKey), getMessage)
}

func getStatusTypeString(status domain.MessageStatus) (str string, err error) {
	switch status {
	case domain.MessageStatusGood:
		return "good", nil
	case domain.MessageStatusWarning:
		return "warning", nil
	case domain.MessageStatusStopper:
		return "danger", nil
	}

	return "", tracerr.Errorf("unknown Message Status Type")
}

func getMessage(text string, status domain.MessageStatus) string {
	dt := time.Now()
	dtf := dt.Format("15:04:05.000 -07 [02/01/2006]")

	sts, err := getStatusTypeString(status)
	if err != nil {
		err := tracerr.Errorf("error getting status type string: %v", err)

		logger.ErrorWoNotifier("%v", err.Error())

		var e error

		sts, e = getStatusTypeString(domain.MessageStatusWarning)
		if e != nil {
			e = tracerr.Errorf("error getting status type string: %v", e)

			logger.ErrorWoNotifier("%v", e.Error())
		}
	}

	appVersion := version.Base()

	msg := `
	{
		"username": "SystemMonitor",
		"attachments": [
			{
				"color": "%s",
				"title": "qfixpt",
				"title_link": "https://api.slack.com/",
				"text": "%s\n%s",
				"fields": [
					{
						"title": "Build",
						"value": "%s",
						"short": false
					}
				]
			}
		]
	}`

	jsonMsg := fmt.Sprintf(msg, sts, text, dtf, appVersion)

	return jsonMsg
}
