package handlers

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/thelinuxer/pgvoyager/internal/database"
	"github.com/thelinuxer/pgvoyager/internal/dbsafe"
	"github.com/thelinuxer/pgvoyager/internal/models"
)

// safeErr is a thin wrapper over dbsafe.SafeErrorMessage so handlers don't
// have to import the package just for one call.
func safeErr(err error) string { return dbsafe.SafeErrorMessage(err) }

func ListConnections(c *gin.Context) {
	manager := database.GetManager()
	connections := manager.List()
	c.JSON(http.StatusOK, connections)
}

func CreateConnection(c *gin.Context) {
	var req models.ConnectionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	conn, err := database.GetManager().Create(&req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": safeErr(err)})
		return
	}

	c.JSON(http.StatusCreated, conn)
}

func TestConnection(c *gin.Context) {
	var req models.TestConnectionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if req.SSLMode == "" {
		req.SSLMode = "prefer"
	}

	if err := database.GetManager().TestConnection(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": safeErr(err), "success": false})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true, "message": "Connection successful"})
}

func GetConnection(c *gin.Context) {
	id := c.Param("id")
	conn, err := database.GetManager().Get(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": safeErr(err)})
		return
	}
	c.JSON(http.StatusOK, conn)
}

func UpdateConnection(c *gin.Context) {
	id := c.Param("id")
	var req models.ConnectionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	conn, err := database.GetManager().Update(id, &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": safeErr(err)})
		return
	}

	c.JSON(http.StatusOK, conn)
}

func DeleteConnection(c *gin.Context) {
	id := c.Param("id")
	if err := database.GetManager().Delete(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": safeErr(err)})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Connection deleted"})
}

func Connect(c *gin.Context) {
	id := c.Param("id")
	if err := database.GetManager().Connect(id); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": safeErr(err)})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Connected successfully"})
}

func Disconnect(c *gin.Context) {
	id := c.Param("id")
	if err := database.GetManager().Disconnect(id); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": safeErr(err)})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Disconnected successfully"})
}

func SwitchDatabase(c *gin.Context) {
	id := c.Param("id")
	var req models.SwitchDatabaseRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	conn, err := database.GetManager().SwitchDatabase(id, req.Database)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": safeErr(err)})
		return
	}

	c.JSON(http.StatusOK, conn)
}

func CreateDatabase(c *gin.Context) {
	id := c.Param("id")
	var req models.CreateDatabaseRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := database.GetManager().CreateDatabase(id, &req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": safeErr(err)})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"name": req.Name})
}

func DropDatabase(c *gin.Context) {
	id := c.Param("id")
	dbName := c.Param("name")
	var req models.DropDatabaseRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		// body optional — default force=false
		req = models.DropDatabaseRequest{}
	}

	if err := database.GetManager().DropDatabase(id, dbName, req.Force); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": safeErr(err)})
		return
	}

	conn, _ := database.GetManager().Get(id)
	c.JSON(http.StatusOK, gin.H{"dropped": dbName, "currentDatabase": conn.Database})
}
