package handler

import (
	"context"
	"net/http"

	"eslogad-be/internal/contract"

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

type RBACService interface {
	CreatePermission(ctx context.Context, req *contract.CreatePermissionRequest) (*contract.PermissionResponse, error)
	UpdatePermission(ctx context.Context, id uuid.UUID, req *contract.UpdatePermissionRequest) (*contract.PermissionResponse, error)
	DeletePermission(ctx context.Context, id uuid.UUID) error
	ListPermissions(ctx context.Context) (*contract.ListPermissionsResponse, error)

	CreateRole(ctx context.Context, req *contract.CreateRoleRequest) (*contract.RoleWithPermissionsResponse, error)
	UpdateRole(ctx context.Context, id uuid.UUID, req *contract.UpdateRoleRequest) (*contract.RoleWithPermissionsResponse, error)
	DeleteRole(ctx context.Context, id uuid.UUID) error
	ListRoles(ctx context.Context) (*contract.ListRolesResponse, error)
	
	// New methods
	GetPermissionsGrouped(ctx context.Context) (*contract.PermissionsGroupedResponse, error)
	CreateOrUpdateRole(ctx context.Context, req *contract.CreateOrUpdateRoleRequest) (*contract.RoleDetailResponse, error)
	GetRoleDetail(ctx context.Context, roleID uuid.UUID) (*contract.RoleDetailResponse, error)
}

type RBACHandler struct{ svc RBACService }

func NewRBACHandler(svc RBACService) *RBACHandler { return &RBACHandler{svc: svc} }

func (h *RBACHandler) CreatePermission(c *gin.Context) {
	var req contract.CreatePermissionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
		return
	}
	resp, err := h.svc.CreatePermission(c.Request.Context(), &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusCreated, contract.BuildSuccessResponse(resp))
}

func (h *RBACHandler) UpdatePermission(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: 400})
		return
	}
	var req contract.UpdatePermissionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: 400})
		return
	}
	resp, err := h.svc.UpdatePermission(c.Request.Context(), id, &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}

func (h *RBACHandler) DeletePermission(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: 400})
		return
	}
	if err := h.svc.DeletePermission(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "deleted"})
}

func (h *RBACHandler) ListPermissions(c *gin.Context) {
	resp, err := h.svc.ListPermissions(c.Request.Context())
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}

func (h *RBACHandler) CreateRole(c *gin.Context) {
	var req contract.CreateRoleRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: 400})
		return
	}
	resp, err := h.svc.CreateRole(c.Request.Context(), &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusCreated, contract.BuildSuccessResponse(resp))
}

func (h *RBACHandler) UpdateRole(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: 400})
		return
	}
	var req contract.UpdateRoleRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: 400})
		return
	}
	resp, err := h.svc.UpdateRole(c.Request.Context(), id, &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}

func (h *RBACHandler) DeleteRole(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: 400})
		return
	}
	if err := h.svc.DeleteRole(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "deleted"})
}

func (h *RBACHandler) ListRoles(c *gin.Context) {
	resp, err := h.svc.ListRoles(c.Request.Context())
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}

// New handlers for the required API endpoints
func (h *RBACHandler) GetPermissionsGrouped(c *gin.Context) {
	resp, err := h.svc.GetPermissionsGrouped(c.Request.Context())
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusOK, resp)
}

func (h *RBACHandler) CreateOrUpdateRole(c *gin.Context) {
	var req contract.CreateOrUpdateRoleRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body: " + err.Error(), Code: 400})
		return
	}
	
	resp, err := h.svc.CreateOrUpdateRole(c.Request.Context(), &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusOK, resp)
}

func (h *RBACHandler) GetRoleDetail(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: 400})
		return
	}
	
	resp, err := h.svc.GetRoleDetail(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusOK, resp)
}
