package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"text/template"

	"github.com/go-telegram-bot-api/telegram-bot-api"
	"github.com/sensu/sensu-go/types"
	"github.com/spf13/cobra"
)

var (
	token            string
	channel          int64
	subject          string
	hookout          bool
	bodyTemplateFile string
	stdin            *os.File

	emailSubjectTemplate = "Sensu Alert - {{.Entity.Name}}/{{.Check.Name}}: {{.Check.State}}"
	emailBodyTemplate    = "{{.Check.Output}}"
)

func main() {
	cmd := &cobra.Command{
		Use:   "sensu-telegram-handler",
		Short: "The Sensu Go Telegram handler for sending an email notification",
		RunE:  run,
	}

	cmd.Flags().StringVarP(&token, "token", "t", "", "the telegram bot token")
	cmd.Flags().Int64VarP(&channel, "channel", "c", -1, "The channel")
	cmd.Flags().BoolVarP(&hookout, "hookout", "H", false, "Include output from check hook(s)")
	cmd.Flags().StringVarP(&bodyTemplateFile, "bodyTemplateFile", "T", "", "A template file to use for the body")

	cmd.Execute()
}

func run(cmd *cobra.Command, args []string) error {
	validationError := checkArgs()
	if validationError != nil {
		return validationError
	}

	if stdin == nil {
		stdin = os.Stdin
	}

	eventJSON, err := ioutil.ReadAll(stdin)
	if err != nil {
		return fmt.Errorf("failed to read stdin: %s", err)
	}

	event := &types.Event{}
	err = json.Unmarshal(eventJSON, event)
	if err != nil {
		return fmt.Errorf("failed to unmarshal stdin data: %s", err)
	}

	if err = event.Validate(); err != nil {
		return fmt.Errorf("failed to validate event: %s", err)
	}

	if !event.HasCheck() {
		return fmt.Errorf("event does not contain check")
	}

	sendMsg(event)

	return nil
}

func checkArgs() error {
	if hookout && len(bodyTemplateFile) > 0 {
		return errors.New("--hookout (-H) and --bodyTemplateFile (-T) are mutually exclusive")
	}
	if hookout {
		emailBodyTemplate = "{{.Check.Output}}\n{{range .Check.Hooks}}Hook Name:  {{.Name}}\nHook Command:  {{.Command}}\n\n{{.Output}}\n\n{{end}}"
	} else if len(bodyTemplateFile) > 0 {
		templateBytes, fileErr := ioutil.ReadFile(bodyTemplateFile)
		if fileErr != nil {
			return fmt.Errorf("failed to read specified template file %s", bodyTemplateFile)
		}
		emailBodyTemplate = string(templateBytes)
	}
	return nil
}

func sendMsg(event *types.Event) error {
	var output string

	bot, botErr := tgbotapi.NewBotAPI(token)
	if botErr != nil {
		return botErr
	}

	subject, subjectErr := resolveTemplate(emailSubjectTemplate, event)
	if subjectErr != nil {
		return subjectErr
	}

	body, bodyErr := resolveTemplate(emailBodyTemplate, event)
	if bodyErr != nil {
		return bodyErr
	}

	output = fmt.Sprintf("%s, %s", subject, body)

	msg := tgbotapi.NewMessage(channel, output)
	_, sendErr := bot.Send(msg)

	return sendErr
}

func resolveTemplate(templateValue string, event *types.Event) (string, error) {
	var resolved bytes.Buffer
	tmpl, err := template.New("test").Parse(templateValue)
	if err != nil {
		panic(err)
	}
	err = tmpl.Execute(&resolved, *event)
	if err != nil {
		panic(err)
	}

	return resolved.String(), nil
}
