package api

import (
	"net/http"
	"strings"

	"github.com/ez-api/ez-api/internal/model"
	"github.com/gin-gonic/gin"
)

type NamespaceRequest struct {
	Name        string `json:"name"`
	Status      string `json:"status"`
	Description string `json:"description"`
}

// CreateNamespace godoc
// @Summary      Create namespace
// @Description  Create a namespace for bindings
// @Tags         admin
// @Accept       json
// @Produce      json
// @Security     AdminAuth
// @Param        namespace  body      NamespaceRequest  true  "Namespace payload"
// @Success      201        {object}  model.Namespace
// @Failure      400        {object}  gin.H
// @Failure      500        {object}  gin.H
// @Router       /admin/namespaces [post]
func (h *Handler) CreateNamespace(c *gin.Context) {
	var req NamespaceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	name := strings.TrimSpace(req.Name)
	if name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "name required"})
		return
	}
	status := strings.TrimSpace(req.Status)
	if status == "" {
		status = "active"
	}

	ns := model.Namespace{
		Name:        name,
		Status:      status,
		Description: strings.TrimSpace(req.Description),
	}
	if err := h.db.Create(&ns).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create namespace", "details": err.Error()})
		return
	}
	c.JSON(http.StatusCreated, ns)
}

// ListNamespaces godoc
// @Summary      List namespaces
// @Description  List all namespaces
// @Tags         admin
// @Produce      json
// @Security     AdminAuth
// @Param        page    query     int     false  "page (1-based)"
// @Param        limit   query     int     false  "limit (default 50, max 200)"
// @Param        search  query     string  false  "search by name/description"
// @Success      200  {array}   model.Namespace
// @Failure      500  {object}  gin.H
// @Router       /admin/namespaces [get]
func (h *Handler) ListNamespaces(c *gin.Context) {
	var out []model.Namespace
	q := h.db.Model(&model.Namespace{}).Order("id desc")
	query := parseListQuery(c)
	q = applyListSearch(q, query.Search, "name", "description")
	q = applyListPagination(q, query)
	if err := q.Find(&out).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list namespaces", "details": err.Error()})
		return
	}
	c.JSON(http.StatusOK, out)
}

// GetNamespace godoc
// @Summary      Get namespace
// @Description  Get a namespace by id
// @Tags         admin
// @Produce      json
// @Security     AdminAuth
// @Param        id   path      int  true  "Namespace ID"
// @Success      200  {object}  model.Namespace
// @Failure      400  {object}  gin.H
// @Failure      404  {object}  gin.H
// @Failure      500  {object}  gin.H
// @Router       /admin/namespaces/{id} [get]
func (h *Handler) GetNamespace(c *gin.Context) {
	id, ok := parseUintParam(c, "id")
	if !ok {
		return
	}
	var ns model.Namespace
	if err := h.db.First(&ns, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "namespace not found"})
		return
	}
	c.JSON(http.StatusOK, ns)
}

type UpdateNamespaceRequest struct {
	Name        *string `json:"name,omitempty"`
	Status      *string `json:"status,omitempty"`
	Description *string `json:"description,omitempty"`
}

// UpdateNamespace godoc
// @Summary      Update namespace
// @Description  Update a namespace
// @Tags         admin
// @Accept       json
// @Produce      json
// @Security     AdminAuth
// @Param        id         path      int                   true  "Namespace ID"
// @Param        namespace  body      UpdateNamespaceRequest true  "Update payload"
// @Success      200        {object}  model.Namespace
// @Failure      400        {object}  gin.H
// @Failure      404        {object}  gin.H
// @Failure      500        {object}  gin.H
// @Router       /admin/namespaces/{id} [put]
func (h *Handler) UpdateNamespace(c *gin.Context) {
	id, ok := parseUintParam(c, "id")
	if !ok {
		return
	}

	var req UpdateNamespaceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	var ns model.Namespace
	if err := h.db.First(&ns, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "namespace not found"})
		return
	}

	update := map[string]any{}
	if req.Name != nil {
		name := strings.TrimSpace(*req.Name)
		if name == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "name required"})
			return
		}
		update["name"] = name
	}
	if req.Status != nil {
		status := strings.TrimSpace(*req.Status)
		if status == "" {
			status = "active"
		}
		update["status"] = status
	}
	if req.Description != nil {
		update["description"] = strings.TrimSpace(*req.Description)
	}
	if len(update) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "no fields to update"})
		return
	}

	if err := h.db.Model(&ns).Updates(update).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update namespace", "details": err.Error()})
		return
	}
	if err := h.db.First(&ns, id).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to reload namespace", "details": err.Error()})
		return
	}
	c.JSON(http.StatusOK, ns)
}

// DeleteNamespace godoc
// @Summary      Delete namespace
// @Description  Delete a namespace and its bindings
// @Tags         admin
// @Produce      json
// @Security     AdminAuth
// @Param        id   path      int  true  "Namespace ID"
// @Success      200  {object}  gin.H
// @Failure      400  {object}  gin.H
// @Failure      404  {object}  gin.H
// @Failure      500  {object}  gin.H
// @Router       /admin/namespaces/{id} [delete]
func (h *Handler) DeleteNamespace(c *gin.Context) {
	id, ok := parseUintParam(c, "id")
	if !ok {
		return
	}
	var ns model.Namespace
	if err := h.db.First(&ns, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "namespace not found"})
		return
	}

	if err := h.db.Delete(&ns).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete namespace", "details": err.Error()})
		return
	}

	if err := h.db.Where("namespace = ?", ns.Name).Delete(&model.Binding{}).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete namespace bindings", "details": err.Error()})
		return
	}
	if err := h.sync.SyncBindings(h.db); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to sync bindings", "details": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"status": "deleted"})
}
