// Copyright Jan Dittberner
// SPDX-License-Identifier: GPL-3.0-or-later
//
// 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 <https://www.gnu.org/licenses/>.
package icinga2

import (
	"fmt"
	"strings"
)

const (
	WarnIcon     = "⚠"
	ErrorIcon    = "❌"
	OKIcon       = "🆗"
	QuestionIcon = "❓"
)

func getIcon(state string) string {
	switch state {
	case "UP", "OK":
		return OKIcon
	case "UNKNOWN":
		return QuestionIcon
	case "WARNING":
		return WarnIcon
	default:
		return ErrorIcon
	}
}

type CouldNotWriteToBufferErr struct {
	Wrapped error
}

func (e CouldNotWriteToBufferErr) Error() string {
	return fmt.Sprintf("could not write to message builder: %s", e.Wrapped)
}

func (e CouldNotWriteToBufferErr) Unwrap() error {
	return e.Wrapped
}

func addOptionalData(message *strings.Builder, p *BaseParameters) error {
	if p.HostAddress != "" {
		if _, err := fmt.Fprintf(message, "<strong>IPv4:</strong> %s<br/>\n", p.HostAddress); err != nil {
			return CouldNotWriteToBufferErr{err}
		}
	}

	if p.HostAddress6 != "" {
		if _, err := fmt.Fprintf(message, "<strong>IPv6:</strong> %s<br/>\n", p.HostAddress6); err != nil {
			return CouldNotWriteToBufferErr{err}
		}
	}

	if p.NotificationAuthorName != "" && p.NotificationComment != "" {
		if _, err := fmt.Fprintf(
			message,
			"Comment by <strong>%s:</strong> %s<br/>\n",
			p.NotificationAuthorName,
			p.NotificationComment,
		); err != nil {
			return CouldNotWriteToBufferErr{err}
		}
	}

	return nil
}

func BuildHostNotification(p *HostParameters) (string, error) {
	message := &strings.Builder{}

	if _, err := fmt.Fprintf(
		message,
		"%s <strong>HOST:</strong> %s is <strong>%s!</strong><br/>\n"+
			"<strong>When:</strong> %s<br/>\n"+
			"<strong>Info:</strong> %s<br/>\n",
		getIcon(p.HostState),
		p.HostDisplayName, p.HostState,
		p.LongDateTime, p.HostOutput); err != nil {
		return "", CouldNotWriteToBufferErr{err}
	}

	if err := addOptionalData(message, &p.BaseParameters); err != nil {
		return "", err
	}

	if p.IcingaWeb2URL.URL != nil {
		icinga2Url := p.IcingaWeb2URL.URL.JoinPath("monitoring/host/show")

		q := icinga2Url.Query()
		q.Set("host", p.Hostname)

		icinga2Url.RawQuery = q.Encode()

		if _, err := message.WriteString(icinga2Url.String()); err != nil {
			return "", CouldNotWriteToBufferErr{err}
		}
	}

	return message.String(), nil
}

func BuildServiceNotification(p *ServiceParameters) (string, error) {
	message := &strings.Builder{}

	if _, err := fmt.Fprintf(
		message,
		"%s <strong>Service:</strong> %s on %s is <strong>%s</strong>.<br/>\n"+
			"<strong>When:</strong> %s<br/>\n"+
			"<strong>Info:</strong> %s<br/>\n",
		getIcon(p.ServiceState), p.ServiceDisplayName, p.HostDisplayName,
		p.ServiceState, p.LongDateTime, p.ServiceOutput,
	); err != nil {
		return "", CouldNotWriteToBufferErr{err}
	}

	if err := addOptionalData(message, &p.BaseParameters); err != nil {
		return "", err
	}

	if p.IcingaWeb2URL.URL != nil {
		icinga2Url := p.IcingaWeb2URL.URL.JoinPath("monitoring/service/show")

		q := icinga2Url.Query()
		q.Set("host", p.Hostname)
		q.Set("service", p.ServiceName)

		icinga2Url.RawQuery = q.Encode()

		if _, err := message.WriteString(icinga2Url.String()); err != nil {
			return "", CouldNotWriteToBufferErr{err}
		}
	}

	return message.String(), nil
}