package heroagent

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"
)

// JobStatus represents the status of a job
type JobStatus string

const (
	// JobStatusNew indicates a newly created job
	JobStatusNew JobStatus = "new"
	// JobStatusActive indicates a job that is currently being processed
	JobStatusActive JobStatus = "active"
	// JobStatusError indicates a job that encountered an error
	JobStatusError JobStatus = "error"
	// JobStatusDone indicates a job that has been completed successfully
	JobStatusDone JobStatus = "done"
)

// Job represents a job to be processed
type Job struct {
	JobID         uint32    `json:"jobid"`
	Topic         string    `json:"topic"`
	Params        string    `json:"params"`
	Status        JobStatus `json:"status"`
	TimeScheduled int64     `json:"time_scheduled"`
	TimeStart     int64     `json:"time_start"`
	TimeEnd       int64     `json:"time_end"`
	Error         string    `json:"error"`
	Result        string    `json:"result"`
}

// RedisConnection wraps Redis connection details
type RedisConnection struct {
	TCPPort        int
	UnixSocketPath string
}

// JobWorker represents a worker that processes jobs
type JobWorker struct {
	id     int
	jobMgr *JobManager
	ctx    context.Context
	wg     *sync.WaitGroup
}

// run is the main worker loop
func (w *JobWorker) run() {
	log.Printf("Worker %d started", w.id)

	ticker := time.NewTicker(w.jobMgr.config.QueuePollInterval)
	defer ticker.Stop()

	for {
		select {
		case <-w.ctx.Done():
			log.Printf("Worker %d stopping", w.id)
			return
		case <-ticker.C:
			// Check for jobs in Redis
			if err := w.checkForJobs(); err != nil {
				log.Printf("Worker %d error checking for jobs: %v", w.id, err)
			}
		}
	}
}

// checkForJobs checks for jobs in Redis
func (w *JobWorker) checkForJobs() error {
	// Get list of queues
	queues, err := w.jobMgr.redisMgr.ListQueues()
	if err != nil {
		return fmt.Errorf("failed to list queues: %w", err)
	}

	// Check each queue for jobs
	for _, topic := range queues {
		// Try to fetch a job from the queue
		job, err := w.jobMgr.redisMgr.FetchNextJob(topic)
		if err != nil {
			// If queue is empty, continue to next queue
			continue
		}

		// Process the job
		if err := w.processJob(job); err != nil {
			log.Printf("Error processing job %d: %v", job.JobID, err)
		}

		// Only process one job at a time
		return nil
	}

	return nil
}

// processJob processes a job
func (w *JobWorker) processJob(job *Job) error {
	log.Printf("Worker %d processing job %d", w.id, job.JobID)

	// Update job status to active
	job.Status = JobStatusActive
	job.TimeStart = time.Now().Unix()

	// Update job in both OurDB and Redis
	if err := w.jobMgr.updateJobInBothStores(job); err != nil {
		return fmt.Errorf("failed to update job status: %w", err)
	}

	// Simulate job processing
	// In a real implementation, this would execute the job based on its parameters
	time.Sleep(1 * time.Second)

	// Complete the job
	job.Status = JobStatusDone
	job.TimeEnd = time.Now().Unix()
	job.Result = fmt.Sprintf("Job %d processed successfully", job.JobID)

	// Update job in OurDB and remove from Redis
	if err := w.jobMgr.completeJobProcessing(job); err != nil {
		return fmt.Errorf("failed to complete job: %w", err)
	}

	log.Printf("Worker %d completed job %d", w.id, job.JobID)
	return nil
}
