package handlers

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

	"github.com/gin-gonic/gin"

	"switchboard-core/store"
	"switchboard-core/workflow"
)

// ── Public Workflow Handlers (v0.3.3) ───────

// WorkflowPublicHandler manages unauthenticated workflow entry endpoints.
type WorkflowPublicHandler struct {
	engine *workflow.Engine
	stores store.Stores
}

// NewWorkflowPublicHandler creates a public workflow handler.
func NewWorkflowPublicHandler(engine *workflow.Engine, stores store.Stores) *WorkflowPublicHandler {
	return &WorkflowPublicHandler{engine: engine, stores: stores}
}

// publicInstanceResponse strips internal metadata from an instance for public consumption.
type publicInstanceResponse struct {
	ID              string          `json:"id"`
	WorkflowID      string          `json:"workflow_id"`
	CurrentStage    string          `json:"current_stage"`
	StageData       json.RawMessage `json:"stage_data"`
	Status          string          `json:"status"`
	EntryToken      *string         `json:"entry_token,omitempty"`
	CreatedAt       any             `json:"created_at"`
	UpdatedAt       any             `json:"updated_at"`
}

// StartPublic creates an anonymous workflow instance.
// POST /api/v1/public/workflows/:id/start
func (h *WorkflowPublicHandler) StartPublic(c *gin.Context) {
	workflowID := c.Param("id")

	var body struct {
		Data json.RawMessage `json:"data"`
	}
	if err := c.ShouldBindJSON(&body); err != nil && err.Error() != "EOF" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
		return
	}
	if len(body.Data) == 0 {
		body.Data = json.RawMessage(`{}`)
	}

	inst, err := h.engine.StartPublic(c.Request.Context(), workflowID, body.Data)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, publicInstanceResponse{
		ID:           inst.ID,
		WorkflowID:   inst.WorkflowID,
		CurrentStage: inst.CurrentStage,
		StageData:    inst.StageData,
		Status:       inst.Status,
		EntryToken:   inst.EntryToken,
		CreatedAt:    inst.CreatedAt,
		UpdatedAt:    inst.UpdatedAt,
	})
}

// ResumePublic returns an active instance by entry token.
// GET /api/v1/public/workflows/resume/:token
func (h *WorkflowPublicHandler) ResumePublic(c *gin.Context) {
	token := c.Param("token")
	if token == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "missing token"})
		return
	}

	inst, err := h.engine.ResumePublic(c.Request.Context(), token)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, publicInstanceResponse{
		ID:           inst.ID,
		WorkflowID:   inst.WorkflowID,
		CurrentStage: inst.CurrentStage,
		StageData:    inst.StageData,
		Status:       inst.Status,
		EntryToken:   inst.EntryToken,
		CreatedAt:    inst.CreatedAt,
		UpdatedAt:    inst.UpdatedAt,
	})
}

// AdvancePublic advances a public instance by entry token.
// POST /api/v1/public/workflows/advance/:token
func (h *WorkflowPublicHandler) AdvancePublic(c *gin.Context) {
	token := c.Param("token")
	if token == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "missing token"})
		return
	}

	var body struct {
		Data json.RawMessage `json:"data"`
	}
	if err := c.ShouldBindJSON(&body); err != nil && err.Error() != "EOF" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
		return
	}
	if len(body.Data) == 0 {
		body.Data = json.RawMessage(`{}`)
	}

	inst, err := h.engine.AdvancePublic(c.Request.Context(), token, body.Data)
	if err != nil {
		if strings.Contains(err.Error(), "requires authenticated access") {
			c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
			return
		}
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, publicInstanceResponse{
		ID:           inst.ID,
		WorkflowID:   inst.WorkflowID,
		CurrentStage: inst.CurrentStage,
		StageData:    inst.StageData,
		Status:       inst.Status,
		EntryToken:   inst.EntryToken,
		CreatedAt:    inst.CreatedAt,
		UpdatedAt:    inst.UpdatedAt,
	})
}
