package services_admin

import (
	dto "astrology-api/dto_admin"
	"astrology-api/notifications"
	"errors"
	"strings"
)

// Notifications the admin panel asks for.
//
// This service holds no wording of its own — every message goes through the
// notifications package, so the admin panel, the apps and this API cannot
// drift into three different phrasings of "your withdrawal was approved".

type NotificationService interface {
	Send(request dto.SendNotificationRequest) (*dto.SendNotificationResponse, error)

	NotifyEvent(request dto.NotifyEventRequest) (*dto.NotifyEventResponse, error)
}

type notificationService struct{}

func NewNotificationService() NotificationService {
	return &notificationService{}
}

//////////////////////////////////////////////////////////////
// Admin message
//////////////////////////////////////////////////////////////

func (s *notificationService) Send(
	request dto.SendNotificationRequest,
) (*dto.SendNotificationResponse, error) {

	audience := strings.ToUpper(strings.TrimSpace(request.Audience))

	title := strings.TrimSpace(request.Title)
	body := strings.TrimSpace(request.Body)

	if title == "" || body == "" {
		return nil, errors.New("title and body are required")
	}

	response := &dto.SendNotificationResponse{
		Audience: audience,
		Queued:   true,
	}

	switch audience {

	case dto.AudienceCustomer:

		if request.UserID == 0 {
			return nil, errors.New("user_id is required for a customer notification")
		}

		notifications.Notify().AdminMessageToCustomer(request.UserID, title, body)

		response.RecipientCount = 1

	case dto.AudienceAstrologer:

		if request.AstrologerID == 0 {
			return nil, errors.New("astrologer_id is required for an astrologer notification")
		}

		notifications.Notify().AdminMessageToAstrologer(request.AstrologerID, title, body)

		response.RecipientCount = 1

	case dto.AudienceAllCustomers:

		response.RecipientCount = notifications.Notify().BroadcastToCustomers(
			title,
			body,
			request.Limit,
		)

	case dto.AudienceAllAstrologers:

		response.RecipientCount = notifications.Notify().BroadcastToAstrologers(
			title,
			body,
			request.Limit,
		)

	default:

		return nil, errors.New(
			"audience must be CUSTOMER, ASTROLOGER, ALL_CUSTOMERS or ALL_ASTROLOGERS",
		)
	}

	return response, nil
}

//////////////////////////////////////////////////////////////
// Panel-handled events
//////////////////////////////////////////////////////////////

// NotifyEvent sends the notification for a decision the admin panel made.
//
// The panel owns these decisions — profile verification and withdrawal
// approval are not implemented in this API — so it reports what it did and
// the API sends the matching message. If either decision ever moves into Go,
// the call site changes to the same notifications helper and this endpoint
// stops being needed.
func (s *notificationService) NotifyEvent(
	request dto.NotifyEventRequest,
) (*dto.NotifyEventResponse, error) {

	event := strings.ToUpper(strings.TrimSpace(request.Event))

	if request.AstrologerID == 0 {
		return nil, errors.New("astrologer_id is required")
	}

	reason := strings.TrimSpace(request.Reason)

	switch event {

	case dto.EventProfileApproved:

		notifications.Notify().ProfileApproved(request.AstrologerID)

	case dto.EventProfileRejected:

		notifications.Notify().ProfileRejected(request.AstrologerID, reason)

	case dto.EventWithdrawApproved:

		if request.Amount <= 0 {
			return nil, errors.New("amount is required for a withdrawal notification")
		}

		notifications.Notify().WithdrawApproved(
			request.AstrologerID,
			request.Amount,
			strings.TrimSpace(request.Reference),
		)

	case dto.EventWithdrawRejected:

		if request.Amount <= 0 {
			return nil, errors.New("amount is required for a withdrawal notification")
		}

		notifications.Notify().WithdrawRejected(
			request.AstrologerID,
			request.Amount,
			reason,
		)

	default:

		return nil, errors.New(
			"event must be PROFILE_APPROVED, PROFILE_REJECTED, " +
				"WITHDRAW_APPROVED or WITHDRAW_REJECTED",
		)
	}

	return &dto.NotifyEventResponse{
		Event:        event,
		AstrologerID: request.AstrologerID,
		Queued:       true,
	}, nil
}
