package notification

import (
	// External
	werr "git.ahall.se/go/wrappederror"

	// Standard
	"log/slog"
	"net/url"
	"slices"
)

type Service interface {
	SetLogger(*slog.Logger)
	GetPrio() int
	GetType() string
	SetPrio(int)
	SetExists(bool) // Exists in database
	Exists() bool   // Exists in database
	String() string
	Send(int, []byte) error
	Update(url.Values) error
	Updated() Service
	Commit()
	JSON() []byte
}

type Manager struct {
	services []Service
	logger   *slog.Logger
}

func NewManager(logger *slog.Logger) (nm Manager) {
	nm.services = []Service{}
	nm.logger = logger
	return
}

func (nm *Manager) AddService(service Service) {
	service.SetExists(true)
	nm.services = append(nm.services, service)
}

func (nm *Manager) Reprioritize() {
	slices.SortFunc(nm.services, func(a, b Service) int {
		if a.GetPrio() < b.GetPrio() {
			return -1
		}
		if a.GetPrio() > b.GetPrio() {
			return 1
		}
		return 0
	})
}

func (nm *Manager) GetService(prio int) *Service {
	for _, svc := range nm.services {
		if svc.GetPrio() == prio {
			return &svc
		}
	}

	return nil
}

func (nm *Manager) RemoveService(prioToRemove int) {
	nm.services = slices.DeleteFunc(nm.services, func(svc Service) bool {
		return svc.GetPrio() == prioToRemove
	})
}

func (nm *Manager) Send(problemID int, msg []byte, fn func(*Service, error)) (err error) {
	for i, service := range nm.services {
		nm.logger.Info("notification", "service", service.GetType(), "prio", service.GetPrio())
		if err = service.Send(problemID, msg); err == nil {
			fn(&nm.services[i], nil)
			break
		} else {
			data := struct {
				ProblemID int
				Msg       []byte
			}{
				problemID,
				msg,
			}
			werr.Wrap(err).WithData(data).Log()
			fn(&nm.services[i], err)
		}
	}

	return
}

func (nm *Manager) Services() (services []Service) {
	return nm.services
}
