package queue

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

	"lune/talentscale/infra/cache"
	"github.com/redis/go-redis/v9"
)

const (
	QueueKey        = "talentscale:jobs"
	DeadLetterKey   = "talentscale:jobs:dead"
	MaxRetries      = 3
)

type Job struct {
	ID        string      `json:"id"`
	Type      string      `json:"type"`
	Payload   interface{} `json:"payload"`
	Retries   int         `json:"retries"`
	Timestamp time.Time   `json:"timestamp"`
}

// PushJob adds a job to the queue
func PushJob(ctx context.Context, jobType string, payload interface{}) error {
	if cache.Client == nil {
		return fmt.Errorf("redis is down")
	}

	job := Job{
		ID:        fmt.Sprintf("job_%d", time.Now().UnixNano()),
		Type:      jobType,
		Payload:   payload,
		Retries:   0,
		Timestamp: time.Now(),
	}

	data, err := json.Marshal(job)
	if err != nil {
		return err
	}

	return cache.Client.LPush(ctx, QueueKey, data).Err()
}

// Worker represents a queue worker
type Worker struct {
	ID      int
	Handler func(Job) error
}

// StartWorkerPool starts multiple workers
func StartWorkerPool(count int, handler func(Job) error) {
	for i := 1; i <= count; i++ {
		worker := &Worker{ID: i, Handler: handler}
		go worker.Start()
	}
	log.Printf("👷 Started %d queue workers", count)
}

func (w *Worker) Start() {
	for {
		if cache.Client == nil {
			time.Sleep(5 * time.Second)
			continue
		}

		// BRPop is blocking pop, better for workers
		result, err := cache.Client.BRPop(context.Background(), 0, QueueKey).Result()
		if err != nil {
			if err != redis.Nil {
				log.Printf("❌ Worker %d: Error popping job: %v", w.ID, err)
			}
			time.Sleep(1 * time.Second)
			continue
		}

		var job Job
		if err := json.Unmarshal([]byte(result[1]), &job); err != nil {
			log.Printf("❌ Worker %d: Error unmarshaling job: %v", w.ID, err)
			continue
		}

		log.Printf("⚙️ Worker %d: Processing job %s (%s)", w.ID, job.ID, job.Type)
		
		if err := w.Handler(job); err != nil {
			log.Printf("❌ Worker %d: Job %s failed: %v", w.ID, job.ID, err)
			w.handleFailure(job)
		} else {
			log.Printf("✅ Worker %d: Job %s completed", w.ID, job.ID)
		}
	}
}

func (w *Worker) handleFailure(job Job) {
	job.Retries++
	if job.Retries < MaxRetries {
		log.Printf("🔄 Retrying job %s (%d/%d)", job.ID, job.Retries, MaxRetries)
		data, _ := json.Marshal(job)
		cache.Client.LPush(context.Background(), QueueKey, data)
	} else {
		log.Printf("💀 Job %s exceeded max retries, moving to Dead Letter Queue", job.ID)
		data, _ := json.Marshal(job)
		cache.Client.LPush(context.Background(), DeadLetterKey, data)
	}
}
