// Filename: internal/domain/upstream/handler.go
package upstream

import (
	"gemini-balancer/internal/errors"
	"gemini-balancer/internal/models"
	"gemini-balancer/internal/response"
	"net/url"
	"strconv"

	"github.com/gin-gonic/gin"
)

type Handler struct {
	service *Service
}

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

// ------ DTOs and Validation ------
type CreateUpstreamRequest struct {
	URL         string `json:"url" binding:"required"`
	Weight      int    `json:"weight" binding:"omitempty,gte=1,lte=1000"`
	Status      string `json:"status" binding:"omitempty,oneof=active inactive"`
	Description string `json:"description"`
}
type UpdateUpstreamRequest struct {
	URL         *string `json:"url"`
	Weight      *int    `json:"weight" binding:"omitempty,gte=1,lte=1000"`
	Status      *string `json:"status" binding:"omitempty,oneof=active inactive"`
	Description *string `json:"description"`
}

func isValidURL(rawURL string) bool {
	u, err := url.ParseRequestURI(rawURL)
	if err != nil {
		return false
	}
	return u.Scheme == "http" || u.Scheme == "https"
}

// --- Handler ---

func (h *Handler) CreateUpstream(c *gin.Context) {
	var req CreateUpstreamRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, errors.NewAPIError(errors.ErrInvalidJSON, err.Error()))
		return
	}
	if !isValidURL(req.URL) {
		response.Error(c, errors.NewAPIError(errors.ErrValidation, "Invalid URL format"))
		return
	}

	upstream := models.UpstreamEndpoint{
		URL:         req.URL,
		Weight:      req.Weight,
		Status:      req.Status,
		Description: req.Description,
	}

	if err := h.service.Create(&upstream); err != nil {
		response.Error(c, errors.ParseDBError(err))
		return
	}
	response.Created(c, upstream)
}

func (h *Handler) ListUpstreams(c *gin.Context) {
	upstreams, err := h.service.List()
	if err != nil {
		response.Error(c, errors.ParseDBError(err))
		return
	}
	response.Success(c, upstreams)
}

func (h *Handler) GetUpstream(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		response.Error(c, errors.NewAPIError(errors.ErrBadRequest, "Invalid ID format"))
		return
	}

	upstream, err := h.service.GetByID(id)
	if err != nil {
		response.Error(c, errors.ParseDBError(err))
		return
	}
	response.Success(c, upstream)
}

func (h *Handler) UpdateUpstream(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		response.Error(c, errors.NewAPIError(errors.ErrBadRequest, "Invalid ID format"))
		return
	}
	var req UpdateUpstreamRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, errors.NewAPIError(errors.ErrInvalidJSON, err.Error()))
		return
	}

	upstream, err := h.service.GetByID(id)
	if err != nil {
		response.Error(c, errors.ParseDBError(err))
		return
	}

	if req.URL != nil {
		if !isValidURL(*req.URL) {
			response.Error(c, errors.NewAPIError(errors.ErrValidation, "Invalid URL format"))
			return
		}
		upstream.URL = *req.URL
	}
	if req.Weight != nil {
		upstream.Weight = *req.Weight
	}
	if req.Status != nil {
		upstream.Status = *req.Status
	}
	if req.Description != nil {
		upstream.Description = *req.Description
	}

	if err := h.service.Update(upstream); err != nil {
		response.Error(c, errors.ParseDBError(err))
		return
	}
	response.Success(c, upstream)
}

func (h *Handler) DeleteUpstream(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		response.Error(c, errors.NewAPIError(errors.ErrBadRequest, "Invalid ID format"))
		return
	}

	rowsAffected, err := h.service.Delete(id)
	if err != nil {
		response.Error(c, errors.ParseDBError(err))
		return
	}
	if rowsAffected == 0 {
		response.Error(c, errors.ErrResourceNotFound)
		return
	}
	response.NoContent(c)
}

// RegisterRoutes

func (h *Handler) RegisterRoutes(rg *gin.RouterGroup) {
	upstreamRoutes := rg.Group("/upstreams")
	{
		upstreamRoutes.POST("/", h.CreateUpstream)
		upstreamRoutes.GET("/", h.ListUpstreams)
		upstreamRoutes.GET("/:id", h.GetUpstream)
		upstreamRoutes.PUT("/:id", h.UpdateUpstream)
		upstreamRoutes.DELETE("/:id", h.DeleteUpstream)
	}
}
