package infra

import (
	"database/sql"
	"time"
)

// JobStatus represents the lifecycle state of a job.
type JobStatus string

const (
	JobStatusPending   JobStatus = "pending"
	JobStatusRunning   JobStatus = "running"
	JobStatusCompleted JobStatus = "completed"
	JobStatusFailed    JobStatus = "failed"
	JobStatusDead      JobStatus = "dead"
)

// Job represents a unit of asynchronous work stored in SQLite.
type Job struct {
	ID          string
	Type        string
	Payload     string    // JSON string
	Status      JobStatus
	Priority    int
	Attempts    int
	MaxAttempts int
	ScheduledAt time.Time
	StartedAt   *time.Time
	CompletedAt *time.Time
	Result      *string
	Error       *string
	CreatedAt   time.Time
}

// JobQueue wraps a *sql.DB and the jobs table name.
type JobQueue struct {
	DB        *sql.DB
	TableName string
}

// JobHandler is the function signature for processing a job.
// Return a non-nil error to trigger retry / fail logic.
type JobHandler func(job Job) error

// EnqueueOption configures optional behaviour of JobEnqueue.
type EnqueueOption func(*enqueueConfig)

type enqueueConfig struct {
	priority    int
	scheduledAt time.Time
	maxAttempts int
}

// WithPriority sets the job priority (higher = processed first).
func WithPriority(p int) EnqueueOption {
	return func(c *enqueueConfig) { c.priority = p }
}

// WithScheduledAt delays execution until the given time.
func WithScheduledAt(t time.Time) EnqueueOption {
	return func(c *enqueueConfig) { c.scheduledAt = t }
}

// WithMaxAttempts sets how many times the job may be attempted before dying.
func WithMaxAttempts(n int) EnqueueOption {
	return func(c *enqueueConfig) { c.maxAttempts = n }
}

// WorkerOption configures optional behaviour of JobWorker / JobWorkerPool.
type WorkerOption func(*workerConfig)

type workerConfig struct {
	pollInterval time.Duration
	jobTypes     []string
}

// WithPollInterval sets how long the worker sleeps between dequeue attempts.
func WithPollInterval(d time.Duration) WorkerOption {
	return func(c *workerConfig) { c.pollInterval = d }
}

// WithJobTypes restricts the worker to the given job types.
// An empty list means all types.
func WithJobTypes(types ...string) WorkerOption {
	return func(c *workerConfig) { c.jobTypes = types }
}
