package handler

import (
	"baron-sso-backend/internal/domain"
	"baron-sso-backend/internal/service"

	"github.com/gofiber/fiber/v2"
)

type UserGroupHandler struct {
	Service service.UserGroupService
}

func NewUserGroupHandler(s service.UserGroupService) *UserGroupHandler {
	return &UserGroupHandler{Service: s}
}

func (h *UserGroupHandler) List(c *fiber.Ctx) error {
	tenantID := c.Params("tenantId")
	groups, err := h.Service.List(c.Context(), tenantID)
	if err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}
	return c.JSON(groups)
}

func (h *UserGroupHandler) Create(c *fiber.Ctx) error {
	tenantID := c.Params("tenantId")
	var req domain.GroupCreateRequest
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid body"})
	}

	group, err := h.Service.Create(c.Context(), tenantID, req.ParentID, req.Name, req.Description, req.UnitType)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}
	return c.Status(fiber.StatusCreated).JSON(group)
}

func (h *UserGroupHandler) Get(c *fiber.Ctx) error {
	id := c.Params("id")
	group, err := h.Service.Get(c.Context(), id)
	if err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, "failed to get group: "+err.Error())
	}
	return c.JSON(group)
}

func (h *UserGroupHandler) Update(c *fiber.Ctx) error {
	tenantID := c.Params("tenantId")
	groupID := c.Params("id")
	var req domain.GroupCreateRequest // Using create request for update fields
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid body"})
	}

	group, err := h.Service.Update(c.Context(), tenantID, groupID, req.Name, req.Description, req.UnitType, req.ParentID)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(group)
}

func (h *UserGroupHandler) Delete(c *fiber.Ctx) error {
	tenantID := c.Params("tenantId")
	groupID := c.Params("id")
	if err := h.Service.Delete(c.Context(), tenantID, groupID); err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}
	return c.SendStatus(fiber.StatusNoContent)
}

func (h *UserGroupHandler) AddMember(c *fiber.Ctx) error {
	groupID := c.Params("id")
	var req struct {
		UserID string `json:"userId"`
	}
	if err := c.BodyParser(&req); err != nil {
		return errorJSON(c, fiber.StatusBadRequest, "userId is required")
	}

	if err := h.Service.AddMember(c.Context(), groupID, req.UserID); err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}
	return c.SendStatus(fiber.StatusOK)
}

func (h *UserGroupHandler) RemoveMember(c *fiber.Ctx) error {
	groupID := c.Params("id")
	userID := c.Params("userId")

	if err := h.Service.RemoveMember(c.Context(), groupID, userID); err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}
	return c.SendStatus(fiber.StatusNoContent)
}

func (h *UserGroupHandler) AssignRole(c *fiber.Ctx) error {
	groupID := c.Params("id")
	var req struct {
		TenantID string `json:"tenantId"`
		Relation string `json:"relation"`
	}
	if err := c.BodyParser(&req); err != nil {
		return errorJSON(c, fiber.StatusBadRequest, "invalid body")
	}

	if err := h.Service.AssignRoleToTenant(c.Context(), groupID, req.TenantID, req.Relation); err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}
	return c.SendStatus(fiber.StatusOK)
}

func (h *UserGroupHandler) ListRoles(c *fiber.Ctx) error {
	groupID := c.Params("id")
	roles, err := h.Service.ListRoles(c.Context(), groupID)
	if err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}
	return c.JSON(roles)
}

func (h *UserGroupHandler) RemoveRole(c *fiber.Ctx) error {
	groupID := c.Params("id")
	tenantID := c.Params("tenantId")
	relation := c.Params("relation")

	if err := h.Service.RemoveRoleFromTenant(c.Context(), groupID, tenantID, relation); err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}
	return c.SendStatus(fiber.StatusNoContent)
}
