// internal/service/market.go
package service

import (
	"context"
	"encoding/json"
	"log"
	"sync"
	"time"
	"websocket-server/internal/model"
	"websocket-server/internal/repository"
	"websocket-server/pkg/websocket"

	"github.com/redis/go-redis/v9"
)

type MarketService struct {
	orderRepo     *repository.OrderRepository
	redis         *redis.Client
	timeThreshold time.Duration
}

func NewMarketService(orderRepo *repository.OrderRepository, redis *redis.Client, timeThreshold time.Duration) *MarketService {
	return &MarketService{
		orderRepo:     orderRepo,
		redis:         redis,
		timeThreshold: timeThreshold,
	}
}

func (s *MarketService) BroadcastOrders(hub *websocket.Hub) {
	ticker := time.NewTicker(2 * time.Second)
	defer ticker.Stop()

	for range ticker.C {
		hub.Mu.RLock()
		clients := make([]*websocket.Client, 0, len(hub.Clients))
		for client := range hub.Clients {
			clients = append(clients, client)
		}
		hub.Mu.RUnlock()

		if len(clients) == 0 {
			continue
		}

		limitGroups := make(map[int][]*websocket.Client)
		for _, client := range clients {
			limitGroups[client.Limit] = append(limitGroups[client.Limit], client)
		}

		var wg sync.WaitGroup
		for limit, groupClients := range limitGroups {
			wg.Add(1)
			go func(lim int, clients []*websocket.Client) {
				defer wg.Done()
				s.broadcastToGroup(hub, lim, clients)
			}(limit, groupClients)
		}
		wg.Wait()
	}
}

func (s *MarketService) broadcastToGroup(hub *websocket.Hub, limit int, clients []*websocket.Client) {
	var wg sync.WaitGroup
	wg.Add(2)

	var buyOrders []model.Order
	var sellOrders []model.Order
	var buyErr, sellErr error

	// خرید و فروش رو موازی بگیر
	go func() {
		defer wg.Done()
		buyOrders, buyErr = s.orderRepo.GetLatestBuyOrders(limit, s.timeThreshold)
		if buyErr != nil {
			log.Printf("Error fetching buy orders: %v", buyErr)
		}
	}()

	go func() {
		defer wg.Done()
		sellOrders, sellErr = s.orderRepo.GetLatestSellOrders(limit, s.timeThreshold)
		if sellErr != nil {
			log.Printf("Error fetching sell orders: %v", sellErr)
		}
	}()

	wg.Wait()

	// اگه هر دو خطا داشتن، return کن
	if buyErr != nil && sellErr != nil {
		log.Println("Both buy and sell orders failed to fetch")
		return
	}

	// اگه یکی خطا داشت، با اون یکی ادامه بده
	if buyOrders == nil {
		buyOrders = []model.Order{}
	}
	if sellOrders == nil {
		sellOrders = []model.Order{}
	}

	hub.Mu.RLock()
	activeClients := make([]*websocket.Client, 0, len(clients))
	for _, client := range clients {
		if hub.Clients[client] {
			activeClients = append(activeClients, client)
		}
	}
	hub.Mu.RUnlock()

	if len(activeClients) == 0 {
		return
	}

	// یک پیام واحد با هر دو لیست
	broadcastData := map[string]interface{}{
		"type":        "update",
		"buy_orders":  buyOrders,
		"sell_orders": sellOrders,
		"timestamp":   time.Now().Unix(),
	}

	data, err := json.Marshal(broadcastData)
	if err != nil {
		log.Println("Error marshaling broadcast data:", err)
		return
	}

	// ارسال به همه clients
	for _, client := range activeClients {
		select {
		case client.Send <- data:
		default:
			log.Printf("Client send buffer full, skipping")
		}
	}
}

func (s *MarketService) GetInitialData(limit int) ([]model.Order, []model.Order, error) {
	var wg sync.WaitGroup
	wg.Add(2)

	var buyOrders []model.Order
	var sellOrders []model.Order
	var buyErr, sellErr error

	// موازی بگیر
	go func() {
		defer wg.Done()
		buyOrders, buyErr = s.orderRepo.GetLatestBuyOrders(limit, s.timeThreshold)
	}()

	go func() {
		defer wg.Done()
		sellOrders, sellErr = s.orderRepo.GetLatestSellOrders(limit, s.timeThreshold)
	}()

	wg.Wait()

	// اگه هر دو خطا داشتن
	if buyErr != nil && sellErr != nil {
		return nil, nil, buyErr
	}

	// اگه یکی خطا داشت، با لیست خالی برگردون
	if buyOrders == nil {
		buyOrders = []model.Order{}
	}
	if sellOrders == nil {
		sellOrders = []model.Order{}
	}

	return buyOrders, sellOrders, nil
}
func (s *MarketService) ListenForMatches(hub *websocket.Hub) {
	ctx := context.Background()
	pubsub := s.redis.Subscribe(ctx, "order_matches")
	defer pubsub.Close()

	log.Println("✓ Listening for match events from Redis (order_matches)...")

	for {
		msg, err := pubsub.ReceiveMessage(ctx)
		if err != nil {
			log.Printf("❌ Redis receive error: %v", err)
			time.Sleep(time.Second)
			continue
		}

		// ✅ پیام از Redis قبلاً type: "match" داره (از matching-engine)
		// فقط forward می‌کنیم
		hub.Broadcast <- []byte(msg.Payload)

		log.Printf("✓ Match event forwarded to WebSocket clients (port 8080)")
	}
}
