package daemon

import (
	"context"
	"errors"
	"log/slog"
	"net/http"
	"strings"
	"time"

	"git.cloudinit.dev/coreci/orca/internal/model"
	"git.cloudinit.dev/coreci/orca/internal/store"
)

// handleJobsCollection handles /v1/jobs.
//   - GET  → list all jobs
//   - POST → not yet supported (job submission is CLI-only in v0.1)
func (s *Server) handleJobsCollection(w http.ResponseWriter, r *http.Request) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()

	switch r.Method {
	case http.MethodGet:
		jobs, err := store.NewJobRepo(s.db).List(ctx)
		if err != nil {
			s.log.Error("list jobs",
				slog.String("component", "daemon"),
				slog.String("error", err.Error()))
			writeError(w, http.StatusInternalServerError, "failed to list jobs")
			return
		}
		if jobs == nil {
			jobs = []*model.Job{}
		}
		writeJSON(w, http.StatusOK, map[string]any{"jobs": jobs, "count": len(jobs)})

	case http.MethodPost:
		// Job submission via HTTP is intentionally not exposed in v0.1.
		// The CLI submits jobs to the local store directly; the daemon
		// exists for observability and lifecycle control.
		writeError(w, http.StatusNotImplemented, "job submission via API is not supported in v0.1; use 'orca job run'")

	default:
		writeError(w, http.StatusMethodNotAllowed, "method not allowed")
	}
}

// handleJobsItem handles /v1/jobs/{id} and /v1/jobs/{id}/tasks.
//   - GET  /v1/jobs/{id}        → job details
//   - GET  /v1/jobs/{id}/tasks  → tasks for a job
func (s *Server) handleJobsItem(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		writeError(w, http.StatusMethodNotAllowed, "method not allowed")
		return
	}
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()

	// Path is /v1/jobs/{id} or /v1/jobs/{id}/tasks
	path := strings.TrimPrefix(r.URL.Path, "/v1/jobs/")
	parts := strings.Split(path, "/")
	if len(parts) == 0 || parts[0] == "" {
		writeError(w, http.StatusBadRequest, "job id required")
		return
	}
	id := parts[0]
	if err := validateID(id); err != nil {
		writeError(w, http.StatusBadRequest, err.Error())
		return
	}

	// /v1/jobs/{id}/tasks
	if len(parts) == 2 && parts[1] == "tasks" {
		tasks, err := store.NewTaskRepo(s.db).ListByJob(ctx, id)
		if err != nil {
			s.log.Error("list tasks for job",
				slog.String("component", "daemon"),
				slog.String("job_id", id),
				slog.String("error", err.Error()))
			writeError(w, http.StatusInternalServerError, "failed to list tasks")
			return
		}
		if tasks == nil {
			tasks = []*model.Task{}
		}
		writeJSON(w, http.StatusOK, map[string]any{"tasks": tasks, "count": len(tasks), "job_id": id})
		return
	}

	// /v1/jobs/{id} (with no further path)
	if len(parts) != 1 {
		writeError(w, http.StatusNotFound, "not found")
		return
	}
	job, err := store.NewJobRepo(s.db).Get(ctx, id)
	if err != nil {
		if errors.Is(err, store.ErrNotFound) {
			writeError(w, http.StatusNotFound, "job not found")
			return
		}
		s.log.Error("get job",
			slog.String("component", "daemon"),
			slog.String("job_id", id),
			slog.String("error", err.Error()))
		writeError(w, http.StatusInternalServerError, "failed to get job")
		return
	}
	writeJSON(w, http.StatusOK, job)
}
