package graph

import (
	"sync"

	"gogs.dmsc.dev/arp/graph/model"
	"gorm.io/gorm"
)

// This file will not be regenerated automatically.
//
// It serves as dependency injection for your app, add any dependencies you require
// here.

// TaskEvent represents a task event for subscriptions
type TaskEvent struct {
	Task      *model.Task
	UserID    uint   // The user who should receive this event (assignee)
	EventType string // "created", "updated", "deleted"
}

// MessageEvent represents a message event for subscriptions
type MessageEvent struct {
	Message     *model.Message
	ReceiverIDs []uint // IDs of users who should receive this event
}

// Resolver is the main resolver struct
type Resolver struct {
	DB *gorm.DB

	// Pub/Sub channels for subscriptions (slice of channels per user for multiple subscriptions)
	taskSubscribers   map[uint][]chan TaskEvent // keyed by user ID
	taskSubscribersMu sync.RWMutex

	messageSubscribers   map[uint][]chan MessageEvent // keyed by user ID
	messageSubscribersMu sync.RWMutex
}

// NewResolver creates a new resolver with initialized pub/sub
func NewResolver(db *gorm.DB) *Resolver {
	return &Resolver{
		DB:                 db,
		taskSubscribers:    make(map[uint][]chan TaskEvent),
		messageSubscribers: make(map[uint][]chan MessageEvent),
	}
}

// SubscribeToTasks registers a user for task events and returns their event channel
// Each subscription gets its own channel to avoid competition between goroutines
func (r *Resolver) SubscribeToTasks(userID uint) <-chan TaskEvent {
	r.taskSubscribersMu.Lock()
	defer r.taskSubscribersMu.Unlock()

	ch := make(chan TaskEvent, 10)
	r.taskSubscribers[userID] = append(r.taskSubscribers[userID], ch)
	return ch
}

// PublishTaskEvent sends a task event to all subscribers for the assignee
func (r *Resolver) PublishTaskEvent(task *model.Task, assigneeID *uint, eventType string) {
	if assigneeID == nil {
		return // No assignee, no one to notify
	}

	event := TaskEvent{
		Task:      task,
		UserID:    *assigneeID,
		EventType: eventType,
	}

	r.taskSubscribersMu.RLock()
	defer r.taskSubscribersMu.RUnlock()

	// Send to all channels for this user
	for _, ch := range r.taskSubscribers[event.UserID] {
		select {
		case ch <- event:
		default:
			// Channel full, skip event
		}
	}
}

// SubscribeToMessages registers a user for message events and returns their event channel
// Each subscription gets its own channel to avoid competition between goroutines
func (r *Resolver) SubscribeToMessages(userID uint) <-chan MessageEvent {
	r.messageSubscribersMu.Lock()
	defer r.messageSubscribersMu.Unlock()

	ch := make(chan MessageEvent, 10)
	r.messageSubscribers[userID] = append(r.messageSubscribers[userID], ch)
	return ch
}

// PublishMessageEvent sends a message event to all subscribers who are receivers
func (r *Resolver) PublishMessageEvent(message *model.Message, receiverIDs []uint) {
	event := MessageEvent{
		Message:     message,
		ReceiverIDs: receiverIDs,
	}

	r.messageSubscribersMu.RLock()
	defer r.messageSubscribersMu.RUnlock()

	for _, userID := range receiverIDs {
		// Send to all channels for this user
		for _, ch := range r.messageSubscribers[userID] {
			select {
			case ch <- event:
			default:
				// Channel full, skip event
			}
		}
	}
}
