package processor

import (
	"context"
	"fmt"
	"net/url"

	"eslogad-be/internal/config"
	"eslogad-be/internal/contract"
	"eslogad-be/internal/entities"

	novu "github.com/novuhq/go-novu/lib"
	"github.com/google/uuid"
)

type NovuProcessor interface {
	CreateSubscriber(ctx context.Context, user *entities.User) error
	UpdateSubscriber(ctx context.Context, user *entities.User) error
	DeleteSubscriber(ctx context.Context, userID uuid.UUID) error
	CreateSubscriberFromContract(ctx context.Context, user *contract.UserResponse) error
	BulkCreateSubscribers(ctx context.Context, users []*entities.User) error
	SendLetterNotification(ctx context.Context, letterID uuid.UUID, recipientUserID uuid.UUID, subject string, body string) error
}

type NovuProcessorImpl struct {
	client *novu.APIClient
	config *config.NovuConfig
}

func NewNovuProcessor(cfg *config.NovuConfig) *NovuProcessorImpl {
	if cfg.APIKey == "" {
		return &NovuProcessorImpl{
			client: nil,
			config: cfg,
		}
	}

	// Create Novu config with backend URL
	novuConfig := &novu.Config{}
	if cfg.BaseURL != "" {
		backendURL, err := url.Parse(cfg.BaseURL)
		if err == nil {
			novuConfig.BackendURL = backendURL
		}
	}

	client := novu.NewAPIClient(cfg.APIKey, novuConfig)

	return &NovuProcessorImpl{
		client: client,
		config: cfg,
	}
}

func (p *NovuProcessorImpl) CreateSubscriber(ctx context.Context, user *entities.User) error {
	if p.client == nil {
		return fmt.Errorf("novu client not initialized")
	}

	subscriberID := user.ID.String()
	
	data := map[string]interface{}{
		"userId":     user.ID.String(),
		"email":      user.Email,
		"isActive":   user.IsActive,
		"createdAt":  user.CreatedAt,
	}

	if user.Departments != nil && len(user.Departments) > 0 {
		depts := make([]map[string]interface{}, len(user.Departments))
		for i, dept := range user.Departments {
			depts[i] = map[string]interface{}{
				"id":   dept.ID.String(),
				"name": dept.Name,
				"code": dept.Code,
			}
		}
		data["departments"] = depts
	}

	subscriber := novu.SubscriberPayload{
		Email:        user.Email,
		FirstName:    user.Name,
		LastName:     "",
		Phone:        "",
		Avatar:       "",
		Data:         data,
	}

	_, err := p.client.SubscriberApi.Identify(ctx, subscriberID, subscriber)
	if err != nil {
		return fmt.Errorf("failed to create subscriber: %w", err)
	}

	return nil
}

func (p *NovuProcessorImpl) UpdateSubscriber(ctx context.Context, user *entities.User) error {
	if p.client == nil {
		return fmt.Errorf("novu client not initialized")
	}

	subscriberID := user.ID.String()
	
	data := map[string]interface{}{
		"userId":     user.ID.String(),
		"email":      user.Email,
		"isActive":   user.IsActive,
		"updatedAt":  user.UpdatedAt,
	}

	if user.Departments != nil && len(user.Departments) > 0 {
		depts := make([]map[string]interface{}, len(user.Departments))
		for i, dept := range user.Departments {
			depts[i] = map[string]interface{}{
				"id":   dept.ID.String(),
				"name": dept.Name,
				"code": dept.Code,
			}
		}
		data["departments"] = depts
	}

	updateData := novu.SubscriberPayload{
		Email:     user.Email,
		FirstName: user.Name,
		LastName:  "",
		Phone:     "",
		Avatar:    "",
		Data:      data,
	}

	_, err := p.client.SubscriberApi.Update(ctx, subscriberID, updateData)
	if err != nil {
		return fmt.Errorf("failed to update subscriber: %w", err)
	}

	return nil
}

func (p *NovuProcessorImpl) DeleteSubscriber(ctx context.Context, userID uuid.UUID) error {
	if p.client == nil {
		return fmt.Errorf("novu client not initialized")
	}

	subscriberID := userID.String()
	
	_, err := p.client.SubscriberApi.Delete(ctx, subscriberID)
	if err != nil {
		return fmt.Errorf("failed to delete subscriber: %w", err)
	}

	return nil
}

func (p *NovuProcessorImpl) CreateSubscriberFromContract(ctx context.Context, user *contract.UserResponse) error {
	if p.client == nil {
		return fmt.Errorf("novu client not initialized")
	}

	subscriberID := user.ID.String()
	
	data := map[string]interface{}{
		"userId":     user.ID.String(),
		"email":      user.Email,
		"isActive":   user.IsActive,
		"createdAt":  user.CreatedAt,
	}

	if user.Roles != nil && len(user.Roles) > 0 {
		roles := make([]map[string]interface{}, len(user.Roles))
		for i, role := range user.Roles {
			roles[i] = map[string]interface{}{
				"id":   role.ID.String(),
				"name": role.Name,
				"code": role.Code,
			}
		}
		data["roles"] = roles
	}

	if user.DepartmentResponse != nil && len(user.DepartmentResponse) > 0 {
		depts := make([]map[string]interface{}, len(user.DepartmentResponse))
		for i, dept := range user.DepartmentResponse {
			depts[i] = map[string]interface{}{
				"id":   dept.ID.String(),
				"name": dept.Name,
				"code": dept.Code,
			}
		}
		data["departments"] = depts
	}

	subscriber := novu.SubscriberPayload{
		Email:        user.Email,
		FirstName:    user.Name,
		LastName:     "",
		Phone:        "",
		Avatar:       "",
		Data:         data,
	}

	_, err := p.client.SubscriberApi.Identify(ctx, subscriberID, subscriber)
	if err != nil {
		return fmt.Errorf("failed to create subscriber from contract: %w", err)
	}

	return nil
}

func (p *NovuProcessorImpl) BulkCreateSubscribers(ctx context.Context, users []*entities.User) error {
	if p.client == nil {
		return fmt.Errorf("novu client not initialized")
	}

	var lastErr error
	successCount := 0
	
	for _, user := range users {
		err := p.CreateSubscriber(ctx, user)
		if err != nil {
			lastErr = err
			continue
		}
		successCount++
	}

	if lastErr != nil && successCount == 0 {
		return fmt.Errorf("failed to create any subscribers, last error: %w", lastErr)
	}

	if lastErr != nil {
		return fmt.Errorf("created %d out of %d subscribers, last error: %w", successCount, len(users), lastErr)
	}

	return nil
}

func (p *NovuProcessorImpl) SendLetterNotification(ctx context.Context, letterID uuid.UUID, recipientUserID uuid.UUID, subject string, body string) error {
	if p.client == nil {
		return fmt.Errorf("novu client not initialized")
	}

	subscriberID := recipientUserID.String()
	
	// Check if subscriber exists, create if not
	_, err := p.client.SubscriberApi.Get(ctx, subscriberID)
	if err != nil {
		// Subscriber doesn't exist, create a basic one
		subscriber := novu.SubscriberPayload{
			Email: fmt.Sprintf("%s@placeholder.com", subscriberID),
		}
		_, err = p.client.SubscriberApi.Identify(ctx, subscriberID, subscriber)
		if err != nil {
			return fmt.Errorf("failed to ensure subscriber exists: %w", err)
		}
	}

	// Prepare notification payload
	url := fmt.Sprintf("en/apps/surat-menyurat/masuk-detail/%s", letterID.String())
	
	payload := map[string]interface{}{
		"subject": subject,
		"body":    body,
		"url":     url,
	}

	// Trigger the notification
	triggerPayload := novu.ITriggerPayloadOptions{
		To:      subscriberID,
		Payload: payload,
	}

	_, err = p.client.EventApi.Trigger(ctx, "notification-dashboard", triggerPayload)
	if err != nil {
		return fmt.Errorf("failed to send letter notification: %w", err)
	}

	return nil
}