package group

import (
	"encoding/json"
	"net/http"

	"github.com/go-chi/chi/v5"
	"github.com/google/uuid"

	"nexavpn/backend/internal/apiutil"
	"nexavpn/backend/internal/audit"
	"nexavpn/backend/internal/requestctx"
)

type Handler struct {
	service *Service
	audit   *audit.Service
}

func NewHandler(service *Service, auditService *audit.Service) *Handler {
	return &Handler{service: service, audit: auditService}
}

func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
	items, err := h.service.List(r.Context())
	if err != nil {
		apiutil.Error(w, http.StatusInternalServerError, "groups_list_failed", "unable to list groups")
		return
	}
	apiutil.JSON(w, http.StatusOK, items)
}

func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
	var input CreateRequest
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		apiutil.Error(w, http.StatusBadRequest, "invalid_json", "invalid request body")
		return
	}

	item, err := h.service.Create(r.Context(), input)
	if err != nil {
		apiutil.Error(w, http.StatusInternalServerError, "group_create_failed", "unable to create group")
		return
	}

	if claims, ok := requestctx.ClaimsFromContext(r.Context()); ok {
		_ = h.audit.Record(r.Context(), audit.Entry{
			ActorUserID: &claims.UserID,
			EntityType:  "group",
			EntityID:    &item.ID,
			EventType:   "admin.group.created",
			Status:      "success",
			Message:     "admin created group",
		})
	}

	apiutil.JSON(w, http.StatusCreated, item)
}

func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
	groupID, err := uuid.Parse(chi.URLParam(r, "id"))
	if err != nil {
		apiutil.Error(w, http.StatusBadRequest, "invalid_group_id", "invalid group id")
		return
	}

	var input UpdateRequest
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		apiutil.Error(w, http.StatusBadRequest, "invalid_json", "invalid request body")
		return
	}

	item, err := h.service.Update(r.Context(), groupID, input)
	if err != nil {
		apiutil.Error(w, http.StatusInternalServerError, "group_update_failed", "unable to update group")
		return
	}

	if claims, ok := requestctx.ClaimsFromContext(r.Context()); ok {
		_ = h.audit.Record(r.Context(), audit.Entry{
			ActorUserID: &claims.UserID,
			EntityType:  "group",
			EntityID:    &groupID,
			EventType:   "admin.group.updated",
			Status:      "success",
			Message:     "admin updated group",
		})
	}

	apiutil.JSON(w, http.StatusOK, item)
}

func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
	groupID, err := uuid.Parse(chi.URLParam(r, "id"))
	if err != nil {
		apiutil.Error(w, http.StatusBadRequest, "invalid_group_id", "invalid group id")
		return
	}

	if err := h.service.Delete(r.Context(), groupID); err != nil {
		apiutil.Error(w, http.StatusInternalServerError, "group_delete_failed", "unable to delete group")
		return
	}

	if claims, ok := requestctx.ClaimsFromContext(r.Context()); ok {
		_ = h.audit.Record(r.Context(), audit.Entry{
			ActorUserID: &claims.UserID,
			EntityType:  "group",
			EntityID:    &groupID,
			EventType:   "admin.group.deleted",
			Status:      "success",
			Message:     "admin deleted group",
		})
	}

	apiutil.JSON(w, http.StatusOK, map[string]any{"ok": true})
}
