package notify

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os/exec"
	"strings"
	"time"

	"git.casaderoll.de/michael/urbm/internal/model"
)

type SecretGetter interface{ Get(string) (string, error) }

type Sender struct {
	Secrets    SecretGetter
	Client     *http.Client
	NotifyPath string
	RunCommand func(context.Context, string, ...string) error
}

func (s *Sender) Send(ctx context.Context, target model.NotificationTarget, title, message, severity string) error {
	if !target.Enabled {
		return nil
	}
	switch target.Type {
	case "unraid":
		importance := "normal"
		if severity == "failed" || severity == "error" {
			importance = "alert"
		} else if severity == "warning" {
			importance = "warning"
		}
		path := s.NotifyPath
		if path == "" {
			path = "/usr/local/emhttp/webGui/scripts/notify"
		}
		args := []string{"-e", "URBM", "-s", title, "-d", message, "-i", importance, "-l", "/Tools/URBM"}
		if s.RunCommand != nil {
			return s.RunCommand(ctx, path, args...)
		}
		return exec.CommandContext(ctx, path, args...).Run()
	case "gotify":
		token, err := s.Secrets.Get(target.TokenRef)
		if err != nil {
			return err
		}
		endpoint, err := url.Parse(strings.TrimRight(target.URL, "/") + "/message")
		if err != nil {
			return err
		}
		query := endpoint.Query()
		query.Set("token", token)
		endpoint.RawQuery = query.Encode()
		priority := 2
		if severity == "warning" {
			priority = 5
		} else if severity == "failed" || severity == "error" {
			priority = 8
		}
		payload, err := json.Marshal(map[string]any{"title": title, "message": message, "priority": priority})
		if err != nil {
			return err
		}
		req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), bytes.NewReader(payload))
		if err != nil {
			return err
		}
		req.Header.Set("Content-Type", "application/json")
		client := s.Client
		if client == nil {
			client = &http.Client{Timeout: 15 * time.Second}
		}
		response, err := client.Do(req)
		if err != nil {
			return err
		}
		defer response.Body.Close()
		if response.StatusCode < 200 || response.StatusCode >= 300 {
			return fmt.Errorf("Gotify returned %s", response.Status)
		}
		return nil
	default:
		return fmt.Errorf("unsupported notification type %q", target.Type)
	}
}
