package handlers

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent"
	"gitea.maison43.duckdns.org/gilles/matosbox/internal/data/ent/champpersonnalise"
)

type champPersonnaliseRequest struct {
	NomChamp  *string `json:"nom_champ"`
	TypeChamp *string `json:"type_champ"`
	Valeur    *string `json:"valeur"`
	Unite     *string `json:"unite"`
}

// @Summary Lister les champs personnalises
// @Tags ChampsPersonnalises
// @Produce json
// @Param id path string true "ID objet"
// @Param page query int false "Page"
// @Param limit query int false "Limite"
// @Success 200 {object} map[string]any
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /objets/{id}/champs_personnalises [get]
func (h *Handler) ListChampsPersonnalises(c *gin.Context) {
	objetID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
		return
	}

	limit, offset, page := parsePagination(c.Query("page"), c.Query("limit"))
	query := h.client.ChampPersonnalise.Query().
		Where(champpersonnalise.ObjetID(objetID))
	total, err := query.Count(c.Request.Context())
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de compter les champs"})
		return
	}

	items, err := query.
		Order(ent.Desc(champpersonnalise.FieldCreatedAt)).
		Limit(limit).
		Offset(offset).
		All(c.Request.Context())
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de lister les champs"})
		return
	}
	respondPaginated(c, items, total, page, limit)
}

// @Summary Creer un champ personnalise
// @Tags ChampsPersonnalises
// @Accept json
// @Produce json
// @Param id path string true "ID objet"
// @Param body body champPersonnaliseRequest true "Champ personnalise"
// @Success 201 {object} ent.ChampPersonnalise
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /objets/{id}/champs_personnalises [post]
func (h *Handler) CreateChampPersonnalise(c *gin.Context) {
	objetID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
		return
	}

	var req champPersonnaliseRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
		return
	}
	if req.NomChamp == nil || *req.NomChamp == "" {
		c.JSON(http.StatusBadRequest, gin.H{"erreur": "le champ nom_champ est obligatoire"})
		return
	}

	create := h.client.ChampPersonnalise.Create().
		SetObjetID(objetID).
		SetNomChamp(*req.NomChamp)

	if req.TypeChamp != nil && *req.TypeChamp != "" {
		parsed, ok := parseTypeChamp(*req.TypeChamp)
		if !ok {
			c.JSON(http.StatusBadRequest, gin.H{"erreur": "type_champ invalide"})
			return
		}
		create.SetTypeChamp(parsed)
	}
	if req.Valeur != nil {
		create.SetNillableValeur(req.Valeur)
	}
	if req.Unite != nil {
		create.SetNillableUnite(req.Unite)
	}

	created, err := create.Save(c.Request.Context())
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de creer le champ"})
		return
	}
	c.JSON(http.StatusCreated, created)
}

// @Summary Mettre a jour un champ personnalise
// @Tags ChampsPersonnalises
// @Accept json
// @Produce json
// @Param id path string true "ID champ"
// @Param body body champPersonnaliseRequest true "Champ personnalise"
// @Success 200 {object} ent.ChampPersonnalise
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /champs_personnalises/{id} [put]
func (h *Handler) UpdateChampPersonnalise(c *gin.Context) {
	champID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
		return
	}

	var req champPersonnaliseRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"})
		return
	}

	update := h.client.ChampPersonnalise.UpdateOneID(champID)
	if req.NomChamp != nil {
		update.SetNomChamp(*req.NomChamp)
	}
	if req.TypeChamp != nil {
		if *req.TypeChamp != "" {
			parsed, ok := parseTypeChamp(*req.TypeChamp)
			if !ok {
				c.JSON(http.StatusBadRequest, gin.H{"erreur": "type_champ invalide"})
				return
			}
			update.SetTypeChamp(parsed)
		}
	}
	if req.Valeur != nil {
		update.SetNillableValeur(req.Valeur)
	}
	if req.Unite != nil {
		update.SetNillableUnite(req.Unite)
	}

	updated, err := update.Save(c.Request.Context())
	if err != nil {
		if ent.IsNotFound(err) {
			c.JSON(http.StatusNotFound, gin.H{"erreur": "champ introuvable"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de mettre a jour le champ"})
		return
	}
	c.JSON(http.StatusOK, updated)
}

// @Summary Supprimer un champ personnalise
// @Tags ChampsPersonnalises
// @Param id path string true "ID champ"
// @Success 204 {string} string "No Content"
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /champs_personnalises/{id} [delete]
func (h *Handler) DeleteChampPersonnalise(c *gin.Context) {
	champID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"erreur": "identifiant invalide"})
		return
	}

	if err := h.client.ChampPersonnalise.DeleteOneID(champID).Exec(c.Request.Context()); err != nil {
		if ent.IsNotFound(err) {
			c.JSON(http.StatusNotFound, gin.H{"erreur": "champ introuvable"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de supprimer le champ"})
		return
	}
	c.Status(http.StatusNoContent)
}

func parseTypeChamp(value string) (champpersonnalise.TypeChamp, bool) {
	switch value {
	case "string":
		return champpersonnalise.TypeChampString, true
	case "int":
		return champpersonnalise.TypeChampInt, true
	case "bool":
		return champpersonnalise.TypeChampBool, true
	case "date":
		return champpersonnalise.TypeChampDate, true
	default:
		return "", false
	}
}
