package notification

import (
	"context"
	"fmt"
)

// Service implements the NotificationService interface
type Service struct {
	client *Client
}

type Model struct {
	Message     string
	Title       string
	Type        string
	Priority    string
	ScheduledAt int64
	Recipient   string
	UserID      string
}

// NewService creates a new notification service
func NewService(client *Client) NotificationService {
	return &Service{
		client: client,
	}
}

// SendNotification sends a notification using the configured client
func (s *Service) SendNotification(ctx context.Context, req *NotificationRequest) (*NotificationResponse, error) {
	return s.client.SendNotification(ctx, req)
}

// SendEmail sends an email notification
func (s *Service) SendEmail(ctx context.Context, model Model) (*NotificationResponse, error) {
	req := &NotificationRequest{
		EventType:   EventTypeEmail,
		Message:     model.Message,
		Title:       model.Title,
		Type:        model.Type,
		Priority:    model.Priority,
		ScheduledAt: model.ScheduledAt,
		Methods: NotificationMethods{
			Email: model.Recipient,
		},
		UserID: model.UserID,
	}

	return s.client.SendNotification(ctx, req)
}

// SendSMS sends an SMS notification
func (s *Service) SendSMS(ctx context.Context, model Model) (*NotificationResponse, error) {
	req := &NotificationRequest{
		EventType:   EventTypeSMS,
		Message:     model.Message,
		Title:       model.Title,
		Type:        model.Type,
		Priority:    model.Priority,
		ScheduledAt: model.ScheduledAt,
		Methods: NotificationMethods{
			SMS: model.Recipient,
		},
		UserID: model.UserID,
	}

	return s.client.SendNotification(ctx, req)
}

// SendPush sends a push notification
func (s *Service) SendPush(ctx context.Context, model Model) (*NotificationResponse, error) {
	req := &NotificationRequest{
		EventType:   EventTypePush,
		Message:     model.Message,
		Title:       model.Title,
		Type:        model.Type,
		Priority:    model.Priority,
		ScheduledAt: model.ScheduledAt,
		Methods: NotificationMethods{
			Push: model.Recipient,
		},
		UserID: model.UserID,
	}

	return s.client.SendNotification(ctx, req)
}

// SendOTP sends an OTP notification
func (s *Service) SendOTP(ctx context.Context, model Model) (*NotificationResponse, error) {
	req := &NotificationRequest{
		EventType:   EventTypeOTP,
		Message:     model.Message,
		Title:       model.Title,
		Type:        model.Type,
		Priority:    model.Priority,
		ScheduledAt: model.ScheduledAt,
		Methods: NotificationMethods{
			OTP: model.Recipient,
		},
		UserID: model.UserID,
	}

	return s.client.SendNotification(ctx, req)
}

// GetNotifications retrieves a list of notifications from the notification service
func (s *Service) GetNotifications(ctx context.Context, req *GetNotificationsRequest) (*NotificationListResponse, error) {
	return s.client.GetNotifications(ctx, req)
}

// GetNotification retrieves a single notification by ID
func (s *Service) GetNotification(ctx context.Context, notificationID string) (*DetailedNotificationResponse, error) {
	return s.client.GetNotification(ctx, notificationID)
}

// MarkSeen marks a notification as seen
func (s *Service) MarkSeen(ctx context.Context, notificationID string) (*MarkSeenResponse, error) {
	return s.client.MarkSeen(ctx, notificationID)
}

// AllMarkSeen marks all notifications as seen for a user
func (s *Service) AllMarkSeen(ctx context.Context, userID string) (*MarkSeenResponse, error) {
	return s.client.AllMarkSeen(ctx, userID)
}

// Health checks if the notification service is available
func (s *Service) Health(ctx context.Context) error {
	// Create a simple test request to check service availability
	testReq := &NotificationRequest{
		EventType:   EventTypeEmail,
		Message:     "health check",
		Title:       "Health Check",
		Type:        "info",
		Priority:    "low",
		ScheduledAt: 0,
		Methods: NotificationMethods{
			Email: "test@example.com",
		},
	}

	// We don't actually send this, just validate the client can create a request
	if err := testReq.Validate(); err != nil {
		return fmt.Errorf("service health check failed: %w", err)
	}

	return nil
}

// notificationBuilder implements the Builder interface
type notificationBuilder struct {
	service   *Service
	request   *NotificationRequest
	hasErrors []error
}

// NewBuilder creates a new notification builder
func (s *Service) NewBuilder() Builder {
	return &notificationBuilder{
		service: s,
		request: &NotificationRequest{
			Methods: NotificationMethods{},
		},
		hasErrors: make([]error, 0),
	}
}

// SetEventType sets the event type
func (b *notificationBuilder) SetEventType(eventType EventType) Builder {
	b.request.EventType = eventType
	return b
}

// SetMessage sets the notification message
func (b *notificationBuilder) SetMessage(message string) Builder {
	b.request.Message = message
	return b
}

// SetUserID sets the user ID
func (b *notificationBuilder) SetUserID(userID string) Builder {
	b.request.UserID = userID
	return b
}

// SetEmail sets the email address
func (b *notificationBuilder) SetEmail(email string) Builder {
	b.request.Methods.Email = email
	return b
}

// SetSMS sets the SMS phone number
func (b *notificationBuilder) SetSMS(phoneNumber string) Builder {
	b.request.Methods.SMS = phoneNumber
	return b
}

// SetPush sets the push device token
func (b *notificationBuilder) SetPush(deviceToken string) Builder {
	b.request.Methods.Push = deviceToken
	return b
}

// SetOTP sets the OTP phone number
func (b *notificationBuilder) SetOTP(phoneNumber string) Builder {
	b.request.Methods.OTP = phoneNumber
	return b
}

// SetTitle sets the notification title
func (b *notificationBuilder) SetTitle(title string) Builder {
	b.request.Title = title
	return b
}

// SetType sets the notification type
func (b *notificationBuilder) SetType(notificationType string) Builder {
	b.request.Type = notificationType
	return b
}

// SetPriority sets the notification priority
func (b *notificationBuilder) SetPriority(priority string) Builder {
	b.request.Priority = priority
	return b
}

// SetScheduledAt sets the scheduled delivery time (0 for immediate)
func (b *notificationBuilder) SetScheduledAt(scheduledAt int64) Builder {
	b.request.ScheduledAt = scheduledAt
	return b
}

// Build creates the notification request
func (b *notificationBuilder) Build() (*NotificationRequest, error) {
	if err := b.request.Validate(); err != nil {
		return nil, fmt.Errorf("failed to build notification request: %w", err)
	}

	return b.request, nil
}

// Send builds and sends the notification
func (b *notificationBuilder) Send(ctx context.Context) (*NotificationResponse, error) {
	req, err := b.Build()
	if err != nil {
		return nil, err
	}

	return b.service.SendNotification(ctx, req)
}
