package notifications

import (
	"encoding/json"
	"strings"

	messaging "github.com/tech/sendico/pkg/messaging/envelope"
	"github.com/tech/sendico/pkg/model"
	nm "github.com/tech/sendico/pkg/model/notification"
	"github.com/tech/sendico/pkg/mservice"
)

type ConfirmationRequestNotification struct {
	messaging.Envelope
	payload model.ConfirmationRequest
}

func (crn *ConfirmationRequestNotification) Serialize() ([]byte, error) {
	data, err := json.Marshal(crn.payload)
	if err != nil {
		return nil, err
	}
	return crn.Wrap(data)
}

type ConfirmationResultNotification struct {
	messaging.Envelope
	payload model.ConfirmationResult
}

func (crn *ConfirmationResultNotification) Serialize() ([]byte, error) {
	data, err := json.Marshal(crn.payload)
	if err != nil {
		return nil, err
	}
	return crn.Wrap(data)
}

type ConfirmationDispatchNotification struct {
	messaging.Envelope
	payload model.ConfirmationRequestDispatch
}

func (cdn *ConfirmationDispatchNotification) Serialize() ([]byte, error) {
	data, err := json.Marshal(cdn.payload)
	if err != nil {
		return nil, err
	}
	return cdn.Wrap(data)
}

func confirmationRequestEvent() model.NotificationEvent {
	return model.NewNotification(mservice.Notifications, nm.NAConfirmationRequest)
}

func confirmationResultEvent(sourceService, rail string) model.NotificationEvent {
	sourceService, rail = normalizeSourceRail(sourceService, rail)
	return model.NewNotification(mservice.Verification, nm.NotificationAction(sourceService+"."+rail))
}

func confirmationDispatchEvent(sourceService, rail string) model.NotificationEvent {
	sourceService, rail = normalizeSourceRail(sourceService, rail)
	return model.NewNotification(mservice.Verification, nm.NotificationAction(sourceService+"."+rail+".dispatch"))
}

func normalizeSourceRail(sourceService, rail string) (string, string) {
	action := strings.TrimSpace(sourceService)
	if action == "" {
		action = "unknown"
	}
	action = strings.ToLower(action)
	rail = strings.TrimSpace(rail)
	if rail == "" {
		rail = "default"
	}
	rail = strings.ToLower(rail)
	return action, rail
}

func NewConfirmationRequestEnvelope(sender string, request *model.ConfirmationRequest) messaging.Envelope {
	var payload model.ConfirmationRequest
	if request != nil {
		payload = *request
	}
	return &ConfirmationRequestNotification{
		Envelope: messaging.CreateEnvelope(sender, confirmationRequestEvent()),
		payload:  payload,
	}
}

func NewConfirmationResultEnvelope(sender string, result *model.ConfirmationResult, sourceService, rail string) messaging.Envelope {
	var payload model.ConfirmationResult
	if result != nil {
		payload = *result
	}
	return &ConfirmationResultNotification{
		Envelope: messaging.CreateEnvelope(sender, confirmationResultEvent(sourceService, rail)),
		payload:  payload,
	}
}

func NewConfirmationDispatchEnvelope(sender string, dispatch *model.ConfirmationRequestDispatch, sourceService, rail string) messaging.Envelope {
	var payload model.ConfirmationRequestDispatch
	if dispatch != nil {
		payload = *dispatch
	}
	return &ConfirmationDispatchNotification{
		Envelope: messaging.CreateEnvelope(sender, confirmationDispatchEvent(sourceService, rail)),
		payload:  payload,
	}
}
