package httpserver

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strings"

	"github.com/toki/oto/services/core/internal/cicdstate"
	otopb "github.com/toki/oto/services/core/oto"
)

func handleCreateJob(store *cicdstate.Store, dispatcher runnerControlDispatcher) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var req struct {
			ID         string            `json:"id"`
			Name       string            `json:"name"`
			RunRequest *otopb.RunRequest `json:"run_request"`
		}
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			writeResponse(w, http.StatusBadRequest, map[string]string{"error": "invalid request body"})
			return
		}
		if req.ID == "" || req.Name == "" {
			writeResponse(w, http.StatusBadRequest, map[string]string{"error": "id and name are required"})
			return
		}
		job, err := store.CreateJob(req.ID, req.Name, runRequestFromJSON(req.RunRequest))
		if err != nil {
			writeResponse(w, http.StatusConflict, map[string]string{"error": err.Error()})
			return
		}
		if dispatcher != nil {
			go dispatcher.DispatchQueuedJobs()
		}
		writeResponse(w, http.StatusCreated, jobToJSON(job))
	}
}

func handleGetJob(store *cicdstate.Store) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		jobID := r.PathValue("id")
		if jobID == "" {
			parts := strings.Split(r.URL.Path, "/")
			if len(parts) >= 5 {
				jobID = parts[4]
			}
		}
		if jobID == "" {
			writeResponse(w, http.StatusBadRequest, map[string]string{"error": "missing job id"})
			return
		}
		job, err := store.GetJob(jobID)
		if err != nil {
			if errors.Is(err, fmt.Errorf("job not found: %s", jobID)) || err.Error() == "job not found: "+jobID {
				writeResponse(w, http.StatusNotFound, map[string]string{"error": "job not found"})
				return
			}
			writeResponse(w, http.StatusInternalServerError, map[string]string{"error": "internal error"})
			return
		}
		writeResponse(w, http.StatusOK, jobToJSON(job))
	}
}

func handleCreateExecution(store *cicdstate.Store) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		jobID := r.PathValue("id")
		if jobID == "" {
			parts := strings.Split(r.URL.Path, "/")
			if len(parts) >= 5 {
				jobID = parts[4]
			}
		}
		if jobID == "" {
			writeResponse(w, http.StatusBadRequest, map[string]string{"error": "missing job id"})
			return
		}
		var req struct {
			ID string `json:"id"`
		}
		_ = json.NewDecoder(r.Body).Decode(&req)
		if req.ID == "" {
			writeResponse(w, http.StatusBadRequest, map[string]string{"error": "execution id is required"})
			return
		}
		exec, err := store.CreateExecution(jobID, req.ID)
		if err != nil {
			writeResponse(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
			return
		}
		writeResponse(w, http.StatusCreated, execToJSON(exec))
	}
}
