package scheduler

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

	"github.com/calendarapi/internal/repository"
	"github.com/calendarapi/internal/utils"
	"github.com/hibiken/asynq"
)

// SubscriptionSyncer performs a subscription sync (used by background worker).
type SubscriptionSyncer interface {
	SyncSubscriptionBackground(ctx context.Context, subscriptionID string) error
}

type ReminderWorker struct {
	queries *repository.Queries
}

func NewReminderWorker(queries *repository.Queries) *ReminderWorker {
	return &ReminderWorker{queries: queries}
}

func (w *ReminderWorker) HandleReminderTask(ctx context.Context, t *asynq.Task) error {
	var payload ReminderPayload
	if err := json.Unmarshal(t.Payload(), &payload); err != nil {
		return fmt.Errorf("unmarshal payload: %w", err)
	}

	ev, err := w.queries.GetEventByID(ctx, utils.ToPgUUID(payload.EventID))
	if err != nil {
		return fmt.Errorf("get event: %w", err)
	}

	if ev.DeletedAt.Valid {
		log.Printf("reminder skipped: event %s deleted", payload.EventID)
		return nil
	}

	log.Printf("reminder triggered: event=%s user=%s title=%s",
		payload.EventID, payload.UserID, ev.Title)

	return nil
}

type SubscriptionSyncWorker struct {
	syncer SubscriptionSyncer
}

func NewSubscriptionSyncWorker(syncer SubscriptionSyncer) *SubscriptionSyncWorker {
	return &SubscriptionSyncWorker{syncer: syncer}
}

func (w *SubscriptionSyncWorker) HandleSubscriptionSync(ctx context.Context, t *asynq.Task) error {
	var payload SubscriptionSyncPayload
	if err := json.Unmarshal(t.Payload(), &payload); err != nil {
		return fmt.Errorf("unmarshal subscription sync payload: %w", err)
	}
	if err := w.syncer.SyncSubscriptionBackground(ctx, payload.SubscriptionID); err != nil {
		return fmt.Errorf("sync subscription %s: %w", payload.SubscriptionID, err)
	}
	log.Printf("subscription sync completed: %s", payload.SubscriptionID)
	return nil
}

func StartWorker(redisAddr string, worker *ReminderWorker, subSyncWorker *SubscriptionSyncWorker) *asynq.Server {
	srv := asynq.NewServer(
		asynq.RedisClientOpt{Addr: redisAddr},
		asynq.Config{
			Concurrency: 10,
			Queues: map[string]int{
				"reminders":     6,
				"subscriptions": 2,
				"default":       3,
			},
			RetryDelayFunc: asynq.DefaultRetryDelayFunc,
		},
	)

	mux := asynq.NewServeMux()
	mux.HandleFunc(TypeReminder, worker.HandleReminderTask)
	if subSyncWorker != nil {
		mux.HandleFunc(TypeSubscriptionSync, subSyncWorker.HandleSubscriptionSync)
	}

	go func() {
		if err := srv.Run(mux); err != nil {
			log.Printf("asynq worker error: %v", err)
		}
	}()

	return srv
}
