package system

import (
	"errors"
	"net/http"

	"github.com/gin-gonic/gin"

	"security-center-backend/internal/pkg/response"
	"security-center-backend/internal/service/jwt"
	settingssvc "security-center-backend/internal/service/settings"
	systemsvc "security-center-backend/internal/service/system"
)

type Handler struct {
	service *systemsvc.Service
}

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

func (h *Handler) GetConfig(c *gin.Context) {
	result, err := h.service.GetConfig(c.Request.Context())
	if err != nil {
		response.Error(c, http.StatusInternalServerError, err.Error())
		return
	}
	if checksum := result.Checksum; checksum != "" {
		c.Header("ETag", checksum)
	}
	response.Success(c, result)
}

func (h *Handler) Branding(c *gin.Context) {
	result, err := h.service.GetBranding(c.Request.Context())
	if err != nil {
		response.Error(c, http.StatusInternalServerError, err.Error())
		return
	}
	response.Success(c, result)
}

func (h *Handler) UpdateConfig(c *gin.Context) {
	var req settingssvc.UpdateInput
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, http.StatusBadRequest, "invalid request body")
		return
	}
	req.ExpectedChecksum = c.GetHeader("If-Match")
	if userID, ok := currentUserID(c); ok {
		req.ActorID = &userID
	}
	result, err := h.service.UpdateConfig(c.Request.Context(), req)
	if err != nil {
		switch {
		case errors.Is(err, settingssvc.ErrVersionConflict):
			response.Error(c, http.StatusConflict, err.Error())
		case errors.Is(err, settingssvc.ErrRepositoryUnavailable):
			response.Error(c, http.StatusServiceUnavailable, err.Error())
		case errors.Is(err, settingssvc.ErrChecksumMismatch):
			response.Error(c, http.StatusPreconditionFailed, err.Error())
		case errors.Is(err, settingssvc.ErrInvalidSettings):
			response.Error(c, http.StatusBadRequest, err.Error())
		default:
			response.Error(c, http.StatusInternalServerError, err.Error())
		}
		return
	}
	if checksum := result.Checksum; checksum != "" {
		c.Header("ETag", checksum)
	}
	response.Success(c, result)
}

func (h *Handler) Health(c *gin.Context) {
	status := h.service.Health(c.Request.Context())
	response.Success(c, status)
}

func (h *Handler) Version(c *gin.Context) {
	info := h.service.Version()
	response.Success(c, info)
}

func currentUserID(c *gin.Context) (uint64, bool) {
	claimsValue, exists := c.Get("current_user")
	if !exists {
		return 0, false
	}
	claims, ok := claimsValue.(*jwt.Claims)
	if !ok {
		return 0, false
	}
	return claims.UserID, true
}
