package slack

import (
	"context"
	"strings"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/nlopes/slack"
	"github.com/pingcap/schrodinger/config"
	"github.com/pingcap/schrodinger/util"
)

// NotifierName defines the name of slack notifier
const NotifierName = "slack"

// Notifier implements a Notifier for Slack notifications.
type Notifier struct {
	conf   *config.Slack
	client *slack.Client
}

// New returns a new Slack notification handler.
func New(conf *config.Slack) (*Notifier, error) {
	if util.IsEmpty(conf.Token) {
		return nil, errors.NotValidf("slack config %v", conf)
	}

	client := slack.New(conf.Token)

	return &Notifier{
		conf:   conf,
		client: client,
	}, nil
}

// StateColor defines the color for notification
type StateColor string

// Define some common status colors
const (
	ErrorColor   StateColor = "danger"
	WarnColor    StateColor = "warning"
	SuccessColor            = "good"
)

// Notification is the content for sending a slack notification
type Notification struct {
	Channel    string
	Username   string
	Title      string
	Text       string
	Color      StateColor
	MarkDownIn []string
}

// Notify implements the Notifier interface.
func (n *Notifier) Notify(ctx context.Context, content interface{}) error {
	notify, ok := content.(Notification)
	if !ok {
		return errors.New("the type of context is not slack.Notilfication")
	}

	attachment := slack.Attachment{
		Title:      notify.Title,
		Text:       notify.Text,
		MarkdownIn: notify.MarkDownIn,
		Color:      string(notify.Color),
	}

	params := slack.PostMessageParameters{
		Username:    notify.Username,
		Attachments: []slack.Attachment{attachment},
		LinkNames:   1,
	}

	channel := strings.TrimSpace(notify.Channel)
	if channel[0] != '#' && channel[0] != '@' {
		channel = "#" + channel
	}

	err := util.RetryOnError(ctx, 10, func() error {
		_, _, err := n.client.PostMessage(channel, notify.Title, params)
		if err != nil {
			return errors.Trace(err)
		}

		return nil
	})

	if err != nil {
		log.Errorf("fail to post message to slack, error: %v", err)
	}

	return nil
}
