package services

import (
	"context"
	"fmt"
	"sync"

	firebase "firebase.google.com/go/v4"
	"firebase.google.com/go/v4/messaging"
	"google.golang.org/api/option"
)

type FCMService struct {
	credentials *CredentialsService
	client      *messaging.Client
	currentKey  string
	mu          sync.RWMutex
}

func NewFCMService(c *CredentialsService) *FCMService {
	return &FCMService{credentials: c}
}

func (s *FCMService) getClient(ctx context.Context) (*messaging.Client, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	// Get Service Account JSON from DB
	jsonKey, err := s.credentials.GetDecryptedKey(ctx, "fcm_service_account")
	if err != nil {
		return nil, fmt.Errorf("fcm credentials missing: %w", err)
	}

	// If initialized and key hasn't changed, return cached client
	if s.client != nil && jsonKey == s.currentKey {
		return s.client, nil
	}

	// Initialize new client
	opt := option.WithCredentialsJSON([]byte(jsonKey))
	app, err := firebase.NewApp(ctx, nil, opt)
	if err != nil {
		return nil, fmt.Errorf("error initializing firebase app: %w", err)
	}

	client, err := app.Messaging(ctx)
	if err != nil {
		return nil, fmt.Errorf("error getting messaging client: %w", err)
	}

	s.client = client
	s.currentKey = jsonKey
	return client, nil
}

// SendPush sends a push notification to a specific token
func (s *FCMService) SendPush(ctx context.Context, token, title, body string, data map[string]string) error {
	client, err := s.getClient(ctx)
	if err != nil {
		return err
	}

	msg := &messaging.Message{
		Token: token,
		Notification: &messaging.Notification{
			Title: title,
			Body:  body,
		},
		Data: data,
	}

	_, err = client.Send(ctx, msg)
	return err
}

// SubscribeToTopic subscribes a token to a topic
func (s *FCMService) SubscribeToTopic(ctx context.Context, tokens []string, topic string) error {
	client, err := s.getClient(ctx)
	if err != nil {
		return err
	}

	_, err = client.SubscribeToTopic(ctx, tokens, topic)
	return err
}
