package handlers

import (
	"errors"
	"net/http"

	"github.com/go-chi/chi/v5"
	"github.com/orchard9/rdev/internal/auth"
	"github.com/orchard9/rdev/internal/domain"
	"github.com/orchard9/rdev/internal/service"
	"github.com/orchard9/rdev/internal/validate"
	"github.com/orchard9/rdev/pkg/api"
)

// ArchitectHandler handles architect orchestration endpoints.
type ArchitectHandler struct {
	architectService *service.ArchitectService
}

// NewArchitectHandler creates a new architect handler.
func NewArchitectHandler(architectService *service.ArchitectService) *ArchitectHandler {
	return &ArchitectHandler{
		architectService: architectService,
	}
}

// Mount registers architect routes.
func (h *ArchitectHandler) Mount(r api.Router) {
	r.Route("/projects/{id}/architect", func(r chi.Router) {
		// All architect operations require execute scope
		r.With(auth.RequireScope(auth.ScopeProjectsExecute, auth.ScopeAdmin)).
			Post("/start", h.StartConversation)
		r.With(auth.RequireScope(auth.ScopeProjectsExecute, auth.ScopeAdmin)).
			Post("/continue/{conversationId}", h.ContinueConversation)
		r.With(auth.RequireScope(auth.ScopeProjectsExecute, auth.ScopeAdmin)).
			Post("/generate-blueprint/{conversationId}", h.GenerateBlueprint)
	})
}

// StartConversationRequest is the request body for POST /projects/{id}/architect/start.
type StartConversationRequest struct {
	Prompt string `json:"prompt"`
}

// StartConversation begins a new architectural conversation.
// POST /projects/{id}/architect/start
func (h *ArchitectHandler) StartConversation(w http.ResponseWriter, r *http.Request) {
	projectID := chi.URLParam(r, "id")

	var req StartConversationRequest
	if err := api.DecodeJSON(r, &req); err != nil {
		api.WriteBadRequest(w, r, "invalid request body")
		return
	}

	v := validate.New()
	v.Required(req.Prompt, "prompt")
	if err := v.Error(); err != nil {
		api.WriteBadRequest(w, r, err.Error())
		return
	}

	conv, err := h.architectService.StartConversation(r.Context(), projectID, req.Prompt)
	if err != nil {
		api.WriteInternalError(w, r, "failed to start conversation")
		return
	}

	api.WriteCreated(w, r, StartConversationResponse{
		ConversationWithMessagesDTO: *toConversationWithMessagesDTO(conv),
	})
}

// ContinueConversationRequest is the request body for POST /projects/{id}/architect/continue/{conversationId}.
type ContinueConversationRequest struct {
	Message string `json:"message"`
}

// ContinueConversation continues an existing architectural conversation.
// POST /projects/{id}/architect/continue/{conversationId}
func (h *ArchitectHandler) ContinueConversation(w http.ResponseWriter, r *http.Request) {
	conversationID := domain.ConversationID(chi.URLParam(r, "conversationId"))

	var req ContinueConversationRequest
	if err := api.DecodeJSON(r, &req); err != nil {
		api.WriteBadRequest(w, r, "invalid request body")
		return
	}

	v := validate.New()
	v.Required(req.Message, "message")
	if err := v.Error(); err != nil {
		api.WriteBadRequest(w, r, err.Error())
		return
	}

	msg, err := h.architectService.ContinueConversation(r.Context(), conversationID, req.Message)
	if err != nil {
		if errors.Is(err, domain.ErrConversationNotFound) {
			api.WriteNotFound(w, r, "conversation not found")
			return
		}
		api.WriteInternalError(w, r, "failed to continue conversation")
		return
	}

	api.WriteCreated(w, r, ContinueConversationResponse{
		Message: toMessageDTO(msg),
	})
}

// GenerateBlueprintRequest is the request body for POST /projects/{id}/architect/generate-blueprint/{conversationId}.
type GenerateBlueprintRequest struct {
	Name string `json:"name"`
}

// GenerateBlueprint generates a structured blueprint from a conversation.
// POST /projects/{id}/architect/generate-blueprint/{conversationId}
func (h *ArchitectHandler) GenerateBlueprint(w http.ResponseWriter, r *http.Request) {
	conversationID := domain.ConversationID(chi.URLParam(r, "conversationId"))

	var req GenerateBlueprintRequest
	if err := api.DecodeJSON(r, &req); err != nil {
		api.WriteBadRequest(w, r, "invalid request body")
		return
	}

	v := validate.New()
	v.Required(req.Name, "name")
	if err := v.Error(); err != nil {
		api.WriteBadRequest(w, r, err.Error())
		return
	}

	blueprint, err := h.architectService.GenerateBlueprint(r.Context(), conversationID, req.Name)
	if err != nil {
		if errors.Is(err, domain.ErrConversationNotFound) {
			api.WriteNotFound(w, r, "conversation not found")
			return
		}
		api.WriteInternalError(w, r, "failed to generate blueprint")
		return
	}

	api.WriteCreated(w, r, GenerateBlueprintResponse{
		Blueprint: toBlueprintDTO(blueprint),
	})
}
