package notifications

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gofrs/uuid/v5"
	"github.com/saveinmed/backend-go/internal/domain"
)

// FCMService implements push notifications via Firebase Cloud Messaging
type FCMService struct {
	serverKey  string
	httpClient *http.Client
	tokens     map[uuid.UUID][]string // userID -> []deviceTokens (in-memory, should be DB in production)
}

// NewFCMService creates a new FCM notification service
func NewFCMService(serverKey string) *FCMService {
	return &FCMService{
		serverKey: serverKey,
		httpClient: &http.Client{
			Timeout: 10 * time.Second,
		},
		tokens: make(map[uuid.UUID][]string),
	}
}

// RegisterToken stores a device token for a user
func (s *FCMService) RegisterToken(ctx context.Context, userID uuid.UUID, token string) error {
	if token == "" {
		return errors.New("token cannot be empty")
	}

	// Check if token already exists
	for _, t := range s.tokens[userID] {
		if t == token {
			return nil // Already registered
		}
	}

	s.tokens[userID] = append(s.tokens[userID], token)
	log.Printf("📲 [FCM] Registered token for user %s: %s...", userID, token[:min(20, len(token))])
	return nil
}

// UnregisterToken removes a device token
func (s *FCMService) UnregisterToken(ctx context.Context, userID uuid.UUID, token string) error {
	tokens := s.tokens[userID]
	for i, t := range tokens {
		if t == token {
			s.tokens[userID] = append(tokens[:i], tokens[i+1:]...)
			log.Printf("📲 [FCM] Unregistered token for user %s", userID)
			return nil
		}
	}
	return nil
}

// FCMMessage represents the FCM request payload
type FCMMessage struct {
	To           string            `json:"to,omitempty"`
	Notification *FCMNotification  `json:"notification,omitempty"`
	Data         map[string]string `json:"data,omitempty"`
}

type FCMNotification struct {
	Title string `json:"title"`
	Body  string `json:"body"`
	Icon  string `json:"icon,omitempty"`
	Click string `json:"click_action,omitempty"`
}

// SendPush sends a push notification to a user
func (s *FCMService) SendPush(ctx context.Context, userID uuid.UUID, title, body string, data map[string]string) error {
	tokens := s.tokens[userID]
	if len(tokens) == 0 {
		log.Printf("📲 [FCM] No tokens registered for user %s, skipping push", userID)
		return nil
	}

	for _, token := range tokens {
		msg := FCMMessage{
			To: token,
			Notification: &FCMNotification{
				Title: title,
				Body:  body,
				Icon:  "/favicon.ico",
			},
			Data: data,
		}

		if err := s.sendToFCM(ctx, msg); err != nil {
			log.Printf("📲 [FCM] Error sending to token %s: %v", token[:min(20, len(token))], err)
			continue
		}
		log.Printf("📲 [FCM] Sent push to user %s: %s", userID, title)
	}

	return nil
}

func (s *FCMService) sendToFCM(ctx context.Context, msg FCMMessage) error {
	// If no server key configured, just log
	if s.serverKey == "" {
		log.Printf("📲 [FCM] (Mock) Would send: %s - %s", msg.Notification.Title, msg.Notification.Body)
		return nil
	}

	body, err := json.Marshal(msg)
	if err != nil {
		return fmt.Errorf("failed to marshal FCM message: %w", err)
	}

	req, err := http.NewRequestWithContext(ctx, "POST", "https://fcm.googleapis.com/fcm/send", nil)
	if err != nil {
		return err
	}

	req.Header.Set("Authorization", "key="+s.serverKey)
	req.Header.Set("Content-Type", "application/json")
	req.Body = http.NoBody // We'd set body here in real implementation

	resp, err := s.httpClient.Do(req)
	if err != nil {
		return fmt.Errorf("FCM request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("FCM returned status %d", resp.StatusCode)
	}

	_ = body // Use body in real implementation
	return nil
}

// NotifyOrderCreated implements NotificationService for FCM
func (s *FCMService) NotifyOrderCreated(ctx context.Context, order *domain.Order, buyer, seller *domain.User) error {
	// Notify seller
	if err := s.SendPush(ctx, seller.ID,
		"🛒 Novo Pedido!",
		fmt.Sprintf("Você recebeu um pedido de R$ %.2f", float64(order.TotalCents)/100),
		map[string]string{
			"type":     "new_order",
			"order_id": order.ID.String(),
		},
	); err != nil {
		log.Printf("Error notifying seller: %v", err)
	}

	// Notify buyer
	if err := s.SendPush(ctx, buyer.ID,
		"✅ Pedido Confirmado!",
		fmt.Sprintf("Seu pedido #%s foi recebido", order.ID.String()[:8]),
		map[string]string{
			"type":     "order_confirmed",
			"order_id": order.ID.String(),
		},
	); err != nil {
		log.Printf("Error notifying buyer: %v", err)
	}

	return nil
}

// NotifyOrderStatusChanged implements NotificationService for FCM
func (s *FCMService) NotifyOrderStatusChanged(ctx context.Context, order *domain.Order, buyer *domain.User) error {
	statusEmoji := map[string]string{
		"Pago":     "💳",
		"Faturado": "📄",
		"Enviado":  "🚚",
		"Entregue": "✅",
	}

	emoji := statusEmoji[string(order.Status)]
	if emoji == "" {
		emoji = "📦"
	}

	return s.SendPush(ctx, buyer.ID,
		fmt.Sprintf("%s Pedido Atualizado", emoji),
		fmt.Sprintf("Seu pedido #%s está: %s", order.ID.String()[:8], string(order.Status)),
		map[string]string{
			"type":     "order_status",
			"order_id": order.ID.String(),
			"status":   string(order.Status),
		},
	)
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
