package handlers

import (
	"net/http"

	"{{GO_MODULE}}/pkg/app"
	"{{GO_MODULE}}/pkg/auth"
	"{{GO_MODULE}}/pkg/httperror"
	"{{GO_MODULE}}/pkg/httpresponse"
	"{{GO_MODULE}}/pkg/logging"
	"{{GO_MODULE}}/pkg/queue"
)

// Persona handles HTTP requests for persona generation.
// All generation is async: validate request, enqueue job, return 202 with job ID.
// Results are delivered via SSE events to the user's `user:<userId>` channel:
//
//   - persona_spec_started:    LLM pipeline started
//   - persona_spec_complete:   Persona profile generated
//   - persona_image_started:   Starting a specific image position
//   - persona_image_progress:  Image position complete with URL
//   - persona_image_complete:  All 20 images generated
//   - persona_video_started:   Starting a video motion type
//   - persona_video_complete:  Video complete with URL
//   - persona_failed:          Generation failed (check error field)
type Persona struct {
	queue     queue.Producer
	jobReader queue.JobReader
	logger    *logging.Logger
}

// NewPersona creates a new Persona handler with injected dependencies.
func NewPersona(q queue.Producer, jr queue.JobReader, logger *logging.Logger) *Persona {
	return &Persona{
		queue:     q,
		jobReader: jr,
		logger:    logger.WithComponent("PersonaHandler"),
	}
}

// GeneratePersonaRequest is the request body for persona generation.
type GeneratePersonaRequest struct {
	// Description is a natural-language persona concept (required).
	// Example: "mysterious woman with dark hair who loves poetry"
	Description string `json:"description" validate:"required,min=3,max=1000"`

	// Gender is the gender identity: "woman", "man", or "non_binary" (required).
	Gender string `json:"gender" validate:"required,oneof=woman man non_binary"`

	// Name is an optional name override for the generated persona.
	Name string `json:"name"`
}

// GeneratePersona queues a persona generation job.
// Returns immediately with job ID. Full lifecycle results come via SSE.
//
// Subscribe to SSE channel `user:<userId>` at /api/{{COMPONENT_NAME}}/events before calling.
// Poll job status at GET /generate/jobs/{id} as a fallback to SSE.
func (h *Persona) GeneratePersona(w http.ResponseWriter, r *http.Request) error {
	var req GeneratePersonaRequest
	if err := app.BindAndValidate(r, &req); err != nil {
		return err
	}

	user := auth.GetUser(r.Context())
	if user == nil {
		return httperror.Unauthorized("authentication required")
	}

	jobID, err := h.queue.Enqueue(r.Context(), "persona_generate", map[string]any{
		"description": req.Description,
		"gender":      req.Gender,
		"name":        req.Name,
		"userID":      user.ID,
	})
	if err != nil {
		h.logger.Error("failed to enqueue persona job", "error", err)
		return httperror.Internal("failed to queue persona generation")
	}

	h.logger.Info("persona generation queued", "jobId", jobID, "userID", user.ID)

	httpresponse.Accepted(w, r, GenerateAccepted{JobID: jobID})
	return nil
}
