package tipos_eventos

import (
	"net/http"

	"photum-backend/internal/db/generated"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/jackc/pgx/v5/pgtype"
)

type Handler struct {
	service *Service
}

func NewHandler(service *Service) *Handler {
	return &Handler{service: service}
}

type EventoResponse struct {
	ID     string          `json:"id"`
	Nome   string          `json:"nome"`
	Precos []PrecoResponse `json:"precos"`
}

type PrecoResponse struct {
	ID                   string  `json:"id"`
	TipoEventoID         string  `json:"tipo_evento_id"`
	FuncaoProfissionalID string  `json:"funcao_profissional_id"`
	FuncaoNome           string  `json:"funcao_nome"`
	Valor                float64 `json:"valor"`
}

func toEventoResponse(e generated.TiposEvento) EventoResponse {
	return EventoResponse{
		ID:   uuid.UUID(e.ID.Bytes).String(),
		Nome: e.Nome,
	}
}

func fromPgNumeric(n pgtype.Numeric) float64 {
	f, _ := n.Float64Value()
	return f.Float64
}

type CreateEventoRequest struct {
	Nome string `json:"nome" binding:"required"`
}

// Create godoc
// @Summary      Create a new event type
// @Tags         tipos_eventos
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        request body CreateEventoRequest true "Nome"
// @Success      201  {object}  EventoResponse
// @Router       /api/tipos-eventos [post]
func (h *Handler) Create(c *gin.Context) {
	var req CreateEventoRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	regiao := c.GetString("regiao")
	event, err := h.service.Create(c.Request.Context(), req.Nome, regiao)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, toEventoResponse(*event))
}

// List godoc
// @Summary      List all event types
// @Tags         tipos_eventos
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Success      200  {array}  EventoResponse
// @Router       /api/tipos-eventos [get]
func (h *Handler) List(c *gin.Context) {
	regiao := c.GetString("regiao")
	events, err := h.service.List(c.Request.Context(), regiao)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	response := []EventoResponse{}
	for _, e := range events {
		eventID := uuid.UUID(e.ID.Bytes).String()

		// Fetch prices for this event
		prices, err := h.service.ListPrices(c.Request.Context(), eventID)
		if err != nil {
			// If fetching prices fails, we log/error (or just return empty prices depending on requirement)
			// For now, failing the request ensures data consistency
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

		pricesResp := []PrecoResponse{}
		for _, p := range prices {
			pricesResp = append(pricesResp, PrecoResponse{
				ID:                   uuid.UUID(p.ID.Bytes).String(),
				TipoEventoID:         uuid.UUID(p.TipoEventoID.Bytes).String(),
				FuncaoProfissionalID: uuid.UUID(p.FuncaoProfissionalID.Bytes).String(),
				FuncaoNome:           p.FuncaoNome,
				Valor:                fromPgNumeric(p.Valor),
			})
		}

		evtResp := toEventoResponse(e)
		evtResp.Precos = pricesResp
		response = append(response, evtResp)
	}
	c.JSON(http.StatusOK, response)
}

// SetPrice godoc
// @Summary      Set price for an event function
// @Tags         tipos_eventos
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        request body PriceInput true "Price Input"
// @Success      200  {object}  map[string]string
// @Router       /api/tipos-eventos/precos [post]
func (h *Handler) SetPrice(c *gin.Context) {
	var req PriceInput
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	regiao := c.GetString("regiao")
	_, err := h.service.SetPrice(c.Request.Context(), req, regiao)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "price set"})
}

// ListPrices godoc
// @Summary      List prices for an event
// @Tags         tipos_eventos
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        id   path      string  true  "Event ID"
// @Success      200  {array}  PrecoResponse
// @Router       /api/tipos-eventos/{id}/precos [get]
func (h *Handler) ListPrices(c *gin.Context) {
	id := c.Param("id")
	prices, err := h.service.ListPrices(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	response := []PrecoResponse{}
	for _, p := range prices {
		response = append(response, PrecoResponse{
			ID:                   uuid.UUID(p.ID.Bytes).String(),
			TipoEventoID:         uuid.UUID(p.TipoEventoID.Bytes).String(),
			FuncaoProfissionalID: uuid.UUID(p.FuncaoProfissionalID.Bytes).String(),
			FuncaoNome:           p.FuncaoNome,
			Valor:                fromPgNumeric(p.Valor),
		})
	}
	c.JSON(http.StatusOK, response)
}

// Update godoc
// @Summary      Update an event type
// @Tags         tipos_eventos
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        id       path      string               true  "Event ID"
// @Param        request  body      CreateEventoRequest  true  "Event Data"
// @Success      200      {object}  EventoResponse
// @Router       /api/tipos-eventos/{id} [put]
func (h *Handler) Update(c *gin.Context) {
	id := c.Param("id")
	var req CreateEventoRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	regiao := c.GetString("regiao")
	event, err := h.service.Update(c.Request.Context(), id, req.Nome, regiao)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, toEventoResponse(*event))
}

// Delete godoc
// @Summary      Delete an event type
// @Tags         tipos_eventos
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        id   path      string  true  "Event ID"
// @Success      204
// @Router       /api/tipos-eventos/{id} [delete]
func (h *Handler) Delete(c *gin.Context) {
	id := c.Param("id")
	regiao := c.GetString("regiao")
	err := h.service.Delete(c.Request.Context(), id, regiao)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusNoContent, nil)
}
