package herojobs

import (
	"context"
	"fmt"
	"time"

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

const (
	defaultRedisURL = "redis://localhost:6379/0"
)

// Factory manages job-related operations, including Redis connectivity and watchdog.
type Factory struct {
	redisClient *redis.Client
	// Add other fields as needed, e.g., for watchdog
}

// NewFactory creates a new Factory instance.
// It takes a redisURL string; if empty, it defaults to defaultRedisURL.
func NewFactory(redisURL string) (*Factory, error) {
	if redisURL == "" {
		redisURL = defaultRedisURL
	}

	opt, err := redis.ParseURL(redisURL)
	if err != nil {
		return nil, fmt.Errorf("invalid redis URL: %w", err)
	}

	client := redis.NewClient(opt)

	// Check connection to Redis
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	_, err = client.Ping(ctx).Result()
	if err != nil {
		return nil, fmt.Errorf("failed to connect to redis at %s: %w", redisURL, err)
	}

	fmt.Printf("Successfully connected to Redis at %s\n", redisURL)

	factory := &Factory{
		redisClient: client,
	}

	// TODO: Properly start the watchdog here
	fmt.Println("Watchdog placeholder: Watchdog would be started here.")

	return factory, nil
}

// Close closes the Redis client connection.
func (f *Factory) Close() error {
	if f.redisClient != nil {
		return f.redisClient.Close()
	}
	return nil
}

// GetJob retrieves a job by its ID from Redis.
func (f *Factory) GetJob(ctx context.Context, jobID string) (string, error) {
	// Example: Assuming jobs are stored as string values
	val, err := f.redisClient.Get(ctx, jobID).Result()
	if err == redis.Nil {
		return "", fmt.Errorf("job with ID %s not found", jobID)
	} else if err != nil {
		return "", fmt.Errorf("failed to get job %s from redis: %w", jobID, err)
	}
	return val, nil
}

// ListJobs lists all job IDs (or a subset) from Redis.
// This is a simplified example; real-world job listing might involve more complex data structures.
func (f *Factory) ListJobs(ctx context.Context) ([]string, error) {
	// Example: List all keys that might represent jobs.
	// In a real application, you'd likely use specific Redis data structures (e.g., sorted sets, hashes)
	// to manage jobs more efficiently and avoid scanning all keys.
	keys, err := f.redisClient.Keys(ctx, "job:*").Result() // Assuming job keys are prefixed with "job:"
	if err != nil {
		return nil, fmt.Errorf("failed to list jobs from redis: %w", err)
	}
	return keys, nil
}

// AddJob adds a new job to Redis.
func (f *Factory) AddJob(ctx context.Context, jobID string, jobData string) error {
	// Example: Store job data as a string
	err := f.redisClient.Set(ctx, jobID, jobData, 0).Err() // 0 for no expiration
	if err != nil {
		return fmt.Errorf("failed to add job %s to redis: %w", jobID, err)
	}
	return nil
}

// DeleteJob deletes a job from Redis.
func (f *Factory) DeleteJob(ctx context.Context, jobID string) error {
	_, err := f.redisClient.Del(ctx, jobID).Result()
	if err != nil {
		return fmt.Errorf("failed to delete job %s from redis: %w", jobID, err)
	}
	return nil
}
