package dashboard

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/desktop/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/desktop/internal/dbaas"
	"github.com/tidbcloud/AgentTeam/desktop/internal/profile"
)

func toDBaaSResponse(s dbaas.Service) dto.DBaaSResponse {
	return dto.DBaaSResponse{
		ID:       s.ID,
		Name:     s.Name,
		Provider: s.Provider,
		APIKey:   s.APIKey,
	}
}

// ---------------------------------------------------------------------------
// GET /dbaas
// ---------------------------------------------------------------------------

type ListDBaaSHandler struct{}

func NewListDBaaSHandler() gin.HandlerFunc {
	return (&ListDBaaSHandler{}).Handle
}

func (h *ListDBaaSHandler) Handle(c *gin.Context) {
	services := profile.Default().DBaaS().All()
	resp := make([]dto.DBaaSResponse, 0, len(services))
	for _, s := range services {
		resp = append(resp, toDBaaSResponse(s))
	}
	c.JSON(http.StatusOK, resp)
}

// ---------------------------------------------------------------------------
// POST /dbaas
// ---------------------------------------------------------------------------

type CreateDBaaSHandler struct{}

func NewCreateDBaaSHandler() gin.HandlerFunc {
	return (&CreateDBaaSHandler{}).Handle
}

func (h *CreateDBaaSHandler) Handle(c *gin.Context) {
	var req dto.DBaaSRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("invalid request body: %v", err)})
		return
	}
	s := dbaasRequestToService(req)
	if err := profile.Default().DBaaS().Add(s); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if stored, ok := profile.Default().DBaaS().Get(s.ID); ok {
		c.JSON(http.StatusCreated, toDBaaSResponse(stored))
		return
	}
	c.JSON(http.StatusCreated, toDBaaSResponse(s))
}

// ---------------------------------------------------------------------------
// GET /dbaas/:id
// ---------------------------------------------------------------------------

type GetDBaaSHandler struct{}

func NewGetDBaaSHandler() gin.HandlerFunc {
	return (&GetDBaaSHandler{}).Handle
}

func (h *GetDBaaSHandler) Handle(c *gin.Context) {
	id := c.Param("id")
	s, ok := profile.Default().DBaaS().Get(id)
	if !ok {
		c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("dbaas service %q not found", id)})
		return
	}
	c.JSON(http.StatusOK, toDBaaSResponse(s))
}

// ---------------------------------------------------------------------------
// PUT /dbaas/:id
// ---------------------------------------------------------------------------

type UpdateDBaaSHandler struct{}

func NewUpdateDBaaSHandler() gin.HandlerFunc {
	return (&UpdateDBaaSHandler{}).Handle
}

func (h *UpdateDBaaSHandler) Handle(c *gin.Context) {
	id := c.Param("id")
	var req dto.DBaaSRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("invalid request body: %v", err)})
		return
	}
	s := dbaasRequestToService(req)
	s.ID = id
	if err := profile.Default().DBaaS().Update(s); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if stored, ok := profile.Default().DBaaS().Get(id); ok {
		c.JSON(http.StatusOK, toDBaaSResponse(stored))
		return
	}
	c.JSON(http.StatusOK, toDBaaSResponse(s))
}

// ---------------------------------------------------------------------------
// DELETE /dbaas/:id
// ---------------------------------------------------------------------------

type DeleteDBaaSHandler struct{}

func NewDeleteDBaaSHandler() gin.HandlerFunc {
	return (&DeleteDBaaSHandler{}).Handle
}

func (h *DeleteDBaaSHandler) Handle(c *gin.Context) {
	id := c.Param("id")
	if err := profile.Default().DBaaS().Delete(id); err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"status": "deleted", "id": id})
}

func dbaasRequestToService(req dto.DBaaSRequest) dbaas.Service {
	return dbaas.Service{
		ID:       req.ID,
		Name:     req.Name,
		Provider: req.Provider,
		APIKey:   req.APIKey,
	}
}
