package notification

import (
	"time"

	"github.com/asaskevich/govalidator"
)

// EventType represents the type of notification event
type EventType string

const (
	EventTypeEmail EventType = "EMAIL"
	EventTypeSMS   EventType = "SMS"
	EventTypePush  EventType = "PUSH"
	EventTypeOTP   EventType = "OTP"
)

// NotificationMethods contains different delivery methods for notifications
type NotificationMethods struct {
	OTP   string `json:"otp,omitempty" valid:"optional"`
	SMS   string `json:"sms,omitempty" valid:"optional"`
	Push  string `json:"push,omitempty" valid:"optional"`
	Email string `json:"email,omitempty" valid:"optional,email"`
}

// NotificationRequest represents the request structure for sending notifications
type NotificationRequest struct {
	UserID      string              `json:"user_id"`
	Title       string              `json:"title"`
	Message     string              `json:"message"`
	Type        string              `json:"type"`
	EventType   EventType           `json:"event_type"`
	Priority    string              `json:"priority"`
	ScheduledAt int64               `json:"scheduled_at"`
	Link        string              `json:"link"`
	Image       string              `json:"image"`
	Metadata    map[string]any      `json:"metadata"`
	Methods     NotificationMethods `json:"methods"`
}

// NotificationResponse represents the successful response from notification service
type NotificationResponse struct {
	Status string `json:"status"`
}

// DetailedNotificationResponse represents a detailed notification response
type DetailedNotificationResponse struct {
	Data struct {
		ID          string            `json:"id"`
		UserID      string            `json:"user_id"`
		Title       string            `json:"title"`
		Message     string            `json:"message"`
		Link        string            `json:"link"`
		Image       string            `json:"image"`
		Type        string            `json:"type"`     // info, warning, alert, reject
		Priority    string            `json:"priority"` // low, medium, important
		EventType   string            `json:"event_type"`
		CreatedAt   time.Time         `json:"created_at"`
		UpdatedAt   time.Time         `json:"updated_at"`
		Methods     map[string]string `json:"methods"`
		Metadata    map[string]any    `json:"metadata"`
		Status      string            `json:"status"` // pending, sent, failed
		Seen        bool              `json:"seen"`
		SeenAt      int64             `json:"seen_at"`
		ScheduledAt int64             `json:"scheduled_at"`
		IsScheduled bool              `json:"is_scheduled"`
	} `json:"data"`
}

// NotificationErrorResponse represents the error response from notification service
type NotificationErrorResponse struct {
	Error string `json:"error"`
}

// Validate validates the notification request
func (nr *NotificationRequest) Validate() error {
	// First run govalidator validation
	if _, err := govalidator.ValidateStruct(nr); err != nil {
		return ErrValidation{Field: "struct", Message: err.Error()}
	}

	// Custom validation: ensure at least one method is provided based on event type
	switch nr.EventType {
	case EventTypeEmail:
		if nr.Methods.Email == "" {
			return ErrValidation{Field: "methods.email", Message: "email address is required for EMAIL event type"}
		}
	case EventTypeSMS:
		if nr.Methods.SMS == "" {
			return ErrValidation{Field: "methods.sms", Message: "SMS number is required for SMS event type"}
		}
	case EventTypePush:
		if nr.Methods.Push == "" {
			return ErrValidation{Field: "methods.push", Message: "push device token is required for PUSH event type"}
		}
	case EventTypeOTP:
		if nr.Methods.OTP == "" {
			return ErrValidation{Field: "methods.otp", Message: "OTP number is required for OTP event type"}
		}
	}

	// Validate scheduled_at: 0 means immediate delivery, otherwise must be future timestamp
	if nr.ScheduledAt < 0 {
		return ErrValidation{Field: "scheduled_at", Message: "scheduled_at cannot be negative"}
	}

	return nil
}

// HasMethod checks if a specific method is configured
func (nm *NotificationMethods) HasMethod(eventType EventType) bool {
	switch eventType {
	case EventTypeEmail:
		return nm.Email != ""
	case EventTypeSMS:
		return nm.SMS != ""
	case EventTypePush:
		return nm.Push != ""
	case EventTypeOTP:
		return nm.OTP != ""
	default:
		return false
	}
}

// GetMethodValue returns the value for a specific method
func (nm *NotificationMethods) GetMethodValue(eventType EventType) string {
	switch eventType {
	case EventTypeEmail:
		return nm.Email
	case EventTypeSMS:
		return nm.SMS
	case EventTypePush:
		return nm.Push
	case EventTypeOTP:
		return nm.OTP
	default:
		return ""
	}
}

// IsImmediate returns true if the notification should be sent immediately (scheduled_at = 0)
func (nr *NotificationRequest) IsImmediate() bool {
	return nr.ScheduledAt == 0
}

// NotificationItem represents a single notification in the list response
type NotificationItem struct {
	ID          string            `json:"id"`
	UserID      string            `json:"user_id"`
	Title       string            `json:"title"`
	Message     string            `json:"message"`
	Link        string            `json:"link"`
	Image       string            `json:"image"`
	Type        string            `json:"type"`
	Priority    string            `json:"priority"`
	EventType   string            `json:"event_type"`
	CreatedAt   string            `json:"created_at"`
	UpdatedAt   string            `json:"updated_at"`
	Methods     map[string]string `json:"methods"`
	Metadata    map[string]any    `json:"metadata"`
	Status      string            `json:"status"`
	ScheduledAt int64             `json:"scheduled_at"`
	IsScheduled bool              `json:"is_scheduled"`
	Seen        bool              `json:"seen"`
	SeenAt      int64             `json:"seen_at"`
}

// NotificationListResponse represents the response from getting notifications list
type NotificationListResponse struct {
	Data       []NotificationItem `json:"data"`
	Pagination PaginationInfo     `json:"pagination"`
}

// PaginationInfo represents pagination information in responses
type PaginationInfo struct {
	Total       int `json:"total"`
	Count       int `json:"count"`
	PerPage     int `json:"per_page"`
	CurrentPage int `json:"current_page"`
	TotalPages  int `json:"total_pages"`
}

// GetNotificationsRequest represents the request parameters for getting notifications
type GetNotificationsRequest struct {
	Status    string `json:"status,omitempty" valid:"optional"`
	Method    string `json:"method,omitempty" valid:"optional"`
	EventType string `json:"event_type,omitempty" valid:"optional"`
	Type      string `json:"type,omitempty" valid:"optional"`
	UserID    string `json:"user_id,omitempty" valid:"optional"`
	Seen      *bool  `json:"seen,omitempty" valid:"optional"`
	Priority  string `json:"priority,omitempty" valid:"optional"`
	Page      int    `json:"page,omitempty" valid:"optional"`
	PerPage   int    `json:"per_page,omitempty" valid:"optional"`
}

// MarkSeenRequest represents the request for marking a notification as seen
type MarkSeenRequest struct {
	NotificationID string `json:"notification_id" valid:"required"`
}

// MarkSeenResponse represents the response from marking a notification as seen
type MarkSeenResponse struct {
	Status string `json:"status"`
}
