package user

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) {
	users, err := h.service.List(r.Context())
	if err != nil {
		apiutil.Error(w, http.StatusInternalServerError, "users_list_failed", "unable to list users")
		return
	}

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

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
	}
	if input.Role == "" {
		input.Role = "user"
	}

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

	if claims, ok := requestctx.ClaimsFromContext(r.Context()); ok {
		_ = h.audit.Record(r.Context(), audit.Entry{
			ActorUserID: &claims.UserID,
			EntityType:  "user",
			EntityID:    &created.ID,
			EventType:   "admin.user.created",
			Status:      "success",
			Message:     "admin created user",
			Metadata: map[string]any{
				"username": created.Username,
			},
		})
	}
	apiutil.JSON(w, http.StatusCreated, created)
}

func (h *Handler) Disable(w http.ResponseWriter, r *http.Request) {
	targetID, err := uuid.Parse(chi.URLParam(r, "id"))
	if err != nil {
		apiutil.Error(w, http.StatusBadRequest, "invalid_user_id", "invalid user id")
		return
	}
	if err := h.service.SetActive(r.Context(), targetID.String(), false); err != nil {
		apiutil.Error(w, http.StatusBadRequest, "user_disable_failed", "unable to disable user")
		return
	}
	if claims, ok := requestctx.ClaimsFromContext(r.Context()); ok {
		_ = h.audit.Record(r.Context(), audit.Entry{
			ActorUserID: &claims.UserID,
			EntityType:  "user",
			EntityID:    &targetID,
			EventType:   "admin.user.disabled",
			Status:      "success",
			Message:     "admin disabled user",
		})
	}
	apiutil.JSON(w, http.StatusOK, map[string]any{"ok": true})
}

func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
	targetID, err := uuid.Parse(chi.URLParam(r, "id"))
	if err != nil {
		apiutil.Error(w, http.StatusBadRequest, "invalid_user_id", "invalid user 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
	}

	updated, err := h.service.Update(r.Context(), targetID.String(), input)
	if err != nil {
		apiutil.Error(w, http.StatusInternalServerError, "user_update_failed", "unable to update user")
		return
	}

	if claims, ok := requestctx.ClaimsFromContext(r.Context()); ok {
		_ = h.audit.Record(r.Context(), audit.Entry{
			ActorUserID: &claims.UserID,
			EntityType:  "user",
			EntityID:    &targetID,
			EventType:   "admin.user.updated",
			Status:      "success",
			Message:     "admin updated user",
		})
	}
	apiutil.JSON(w, http.StatusOK, updated)
}

func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
	targetID, err := uuid.Parse(chi.URLParam(r, "id"))
	if err != nil {
		apiutil.Error(w, http.StatusBadRequest, "invalid_user_id", "invalid user id")
		return
	}
	if err := h.service.Delete(r.Context(), targetID.String()); err != nil {
		apiutil.Error(w, http.StatusInternalServerError, "user_delete_failed", "unable to delete user")
		return
	}
	if claims, ok := requestctx.ClaimsFromContext(r.Context()); ok {
		_ = h.audit.Record(r.Context(), audit.Entry{
			ActorUserID: &claims.UserID,
			EntityType:  "user",
			EntityID:    &targetID,
			EventType:   "admin.user.deleted",
			Status:      "success",
			Message:     "admin deleted user",
		})
	}
	apiutil.JSON(w, http.StatusOK, map[string]any{"ok": true})
}

func (h *Handler) Enable(w http.ResponseWriter, r *http.Request) {
	targetID, err := uuid.Parse(chi.URLParam(r, "id"))
	if err != nil {
		apiutil.Error(w, http.StatusBadRequest, "invalid_user_id", "invalid user id")
		return
	}
	if err := h.service.SetActive(r.Context(), targetID.String(), true); err != nil {
		apiutil.Error(w, http.StatusBadRequest, "user_enable_failed", "unable to enable user")
		return
	}
	if claims, ok := requestctx.ClaimsFromContext(r.Context()); ok {
		_ = h.audit.Record(r.Context(), audit.Entry{
			ActorUserID: &claims.UserID,
			EntityType:  "user",
			EntityID:    &targetID,
			EventType:   "admin.user.enabled",
			Status:      "success",
			Message:     "admin enabled user",
		})
	}
	apiutil.JSON(w, http.StatusOK, map[string]any{"ok": true})
}
