package pages

import (
	"fmt"
	"log"

	"git.threefold.info/herocode/heroagent/pkg/herojobs"
	"github.com/gofiber/fiber/v2"
)

// JobDisplayInfo represents information about a job for display purposes
type JobDisplayInfo struct {
	JobID         string `json:"jobid"`
	CircleID      string `json:"circleid"`
	Topic         string `json:"topic"`
	Status        string `json:"status"`
	SessionKey    string `json:"sessionkey"`
	Params        string `json:"params"`
	ParamsType    string `json:"paramstype"`
	Result        string `json:"result"`
	Error         string `json:"error"`
	TimeScheduled int64  `json:"time_scheduled"`
	TimeStart     int64  `json:"time_start"`
	TimeEnd       int64  `json:"time_end"`
	Timeout       int64  `json:"timeout"`
}

// JobHandler handles job-related page routes
type JobHandler struct {
	client *herojobs.RedisClient
	logger *log.Logger
}

// NewJobHandler creates a new job handler with the provided socket path
func NewJobHandler(redisAddr string, logger *log.Logger) (*JobHandler, error) {
	// Assuming SSL is false as per README example herojobs.NewRedisClient("localhost:6379", false)
	// This might need to be configurable later.
	client, err := herojobs.NewRedisClient(redisAddr, false)
	if err != nil {
		return nil, fmt.Errorf("failed to create HeroJobs Redis client: %w", err)
	}

	return &JobHandler{
		client: client,
		logger: logger,
	}, nil
}

// RegisterRoutes registers job page routes
func (h *JobHandler) RegisterRoutes(app *fiber.App) {
	// Register routes for /jobs
	jobs := app.Group("/jobs")
	jobs.Get("/", h.getJobsPage)
	jobs.Get("/list", h.getJobsList)

	// Register the same routes under /admin/jobs for consistency
	adminJobs := app.Group("/admin/jobs")
	adminJobs.Get("/", h.getJobsPage)
	adminJobs.Get("/list", h.getJobsList)
}

// getJobsPage renders the jobs page
func (h *JobHandler) getJobsPage(c *fiber.Ctx) error {
	// Assuming h.client (RedisClient) is valid if NewJobHandler succeeded.
	// The client is connected on creation. A Ping method could be used here for a health check if available.
	// The previous connect/close logic per-request is removed.
	var warning string // This will be empty unless a new check (e.g., Ping) sets it.
	return c.Render("admin/jobs", fiber.Map{
		"title":   "Jobs",
		"warning": warning, // warning will be empty for now
		"error":   "",
	})
}

// getJobsList returns the jobs list fragment for AJAX updates
func (h *JobHandler) getJobsList(c *fiber.Ctx) error {
	// Get parameters from query
	circleID := c.Query("circleid", "")
	topic := c.Query("topic", "")

	// Get jobs
	jobs, err := h.getJobsData(circleID, topic)
	if err != nil {
		h.logger.Printf("Error getting jobs: %v", err)
		// Return the error in the template
		return c.Render("admin/jobs_list_fragment", fiber.Map{
			"error": fmt.Sprintf("Failed to get jobs: %v", err),
			"jobs":  []JobDisplayInfo{},
		})
	}

	// Render only the jobs fragment
	return c.Render("admin/jobs_list_fragment", fiber.Map{
		"jobs": jobs,
	})
}

// getJobsData gets job data from the HeroJobs server
func (h *JobHandler) getJobsData(circleID, topic string) ([]JobDisplayInfo, error) {
	// Assuming h.client (RedisClient) is already connected (established by NewJobHandler).
	// It should not be closed here as it's a long-lived client.
	// Connect() and Close() calls per-request are removed.

	// If circleID and topic are not provided, try to list all jobs
	if circleID == "" && topic == "" {
		// Try to get some default jobs
		defaultCircles := []string{"default", "system"}
		defaultTopics := []string{"default", "system"}

		var allJobs []JobDisplayInfo

		// Try each combination
		for _, circle := range defaultCircles {
			for _, t := range defaultTopics {
				jobIDs, err := h.client.ListJobs(circle, t)
				if err != nil {
					h.logger.Printf("Could not list jobs for circle=%s, topic=%s: %v", circle, t, err)
					continue
				}

				for _, jobID := range jobIDs {
					job, err := h.client.GetJob(jobID)
					if err != nil {
						h.logger.Printf("Error getting job %s: %v", jobID, err)
						continue
					}

					allJobs = append(allJobs, JobDisplayInfo{
						JobID:         fmt.Sprintf("%d", job.JobID),
						CircleID:      job.CircleID,
						Topic:         job.Topic,
						Status:        string(job.Status),
						SessionKey:    job.SessionKey,
						Params:        job.Params,
						ParamsType:    string(job.ParamsType),
						Result:        job.Result,
						Error:         job.Error,
						TimeScheduled: job.TimeScheduled,
						TimeStart:     job.TimeStart,
						TimeEnd:       job.TimeEnd,
						Timeout:       job.Timeout,
					})
				}
			}
		}

		return allJobs, nil
	} else if circleID == "" || topic == "" {
		// If only one of the parameters is provided, we can't list jobs
		return []JobDisplayInfo{}, nil
	}

	// List jobs
	jobIDs, err := h.client.ListJobs(circleID, topic)
	if err != nil {
		return nil, fmt.Errorf("failed to list jobs: %w", err)
	}

	// Get details for each job
	jobsList := make([]JobDisplayInfo, 0, len(jobIDs))
	for _, jobID := range jobIDs {
		job, err := h.client.GetJob(jobID)
		if err != nil {
			h.logger.Printf("Error getting job %s: %v", jobID, err)
			continue
		}

		jobInfo := JobDisplayInfo{
			JobID:         fmt.Sprintf("%d", job.JobID),
			CircleID:      job.CircleID,
			Topic:         job.Topic,
			Status:        string(job.Status),
			SessionKey:    job.SessionKey,
			Params:        job.Params,
			ParamsType:    string(job.ParamsType),
			Result:        job.Result,
			Error:         job.Error,
			TimeScheduled: job.TimeScheduled,
			TimeStart:     job.TimeStart,
			TimeEnd:       job.TimeEnd,
			Timeout:       job.Timeout,
		}
		jobsList = append(jobsList, jobInfo)
	}

	return jobsList, nil
}
