package handler

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

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

type RelyingPartyHandler struct {
	Service     service.RelyingPartyService
	KratosAdmin service.KratosAdminService
}

func NewRelyingPartyHandler(s service.RelyingPartyService, kratos service.KratosAdminService) *RelyingPartyHandler {
	return &RelyingPartyHandler{Service: s, KratosAdmin: kratos}
}

func (h *RelyingPartyHandler) Create(c *fiber.Ctx) error {
	tenantID := c.Params("tenantId")
	if tenantID == "" {
		return errorJSON(c, fiber.StatusBadRequest, "tenantId is required")
	}

	var req domain.HydraClient
	if err := c.BodyParser(&req); err != nil {
		return errorJSON(c, fiber.StatusBadRequest, "invalid request body")
	}

	rp, err := h.Service.Create(c.Context(), tenantID, req)
	if err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}

	return c.Status(fiber.StatusCreated).JSON(rp)
}

func (h *RelyingPartyHandler) ListAll(c *fiber.Ctx) error {
	profile, ok := c.Locals("user_profile").(*domain.UserProfileResponse)
	if !ok {
		return errorJSON(c, fiber.StatusUnauthorized, "unauthorized: user profile not found in context")
	}

	var rps []domain.RelyingParty
	var err error
	role := domain.NormalizeRole(profile.Role)

	if role == domain.RoleSuperAdmin {
		rps, err = h.Service.ListAll(c.Context())
	} else if role == "tenant_admin" && profile.TenantID != nil {
		rps, err = h.Service.List(c.Context(), *profile.TenantID)
	} else {
		slog.Warn("Forbidden access to all applications", "userID", profile.ID, "role", role)
		return errorJSON(c, fiber.StatusForbidden, "forbidden: insufficient role to list all applications")
	}

	if err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}

	return c.JSON(rps)
}

func (h *RelyingPartyHandler) List(c *fiber.Ctx) error {
	tenantID := c.Params("tenantId")
	if tenantID == "" {
		return errorJSON(c, fiber.StatusBadRequest, "tenantId is required")
	}

	rps, err := h.Service.List(c.Context(), tenantID)
	if err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}

	return c.JSON(rps)
}

func (h *RelyingPartyHandler) Get(c *fiber.Ctx) error {
	id := c.Params("id")
	rp, hydraClient, err := h.Service.Get(c.Context(), id)
	if err != nil {
		return errorJSON(c, fiber.StatusNotFound, "relying party not found")
	}

	return c.JSON(fiber.Map{
		"relyingParty": rp,
		"oauth2Config": hydraClient,
	})
}

func (h *RelyingPartyHandler) Update(c *fiber.Ctx) error {
	id := c.Params("id")
	var req domain.HydraClient
	if err := c.BodyParser(&req); err != nil {
		return errorJSON(c, fiber.StatusBadRequest, "invalid request body")
	}

	rp, err := h.Service.Update(c.Context(), id, req)
	if err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}

	return c.JSON(rp)
}

func (h *RelyingPartyHandler) Delete(c *fiber.Ctx) error {
	id := c.Params("id")
	if err := h.Service.Delete(c.Context(), id); err != nil {
		return errorJSON(c, fiber.StatusInternalServerError, err.Error())
	}

	return c.SendStatus(fiber.StatusNoContent)
}
