package handler

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/warmbly/warmbly/internal/api/middleware"
	"github.com/warmbly/warmbly/internal/errx"
	"github.com/warmbly/warmbly/internal/models"
)

// User-facing endpoints under /v1/organizations/:orgId/limit-requests.

// SubmitLimitIncreaseRequest is POST /v1/organizations/:orgId/limit-requests.
func (h *Handler) SubmitLimitIncreaseRequest(c *gin.Context) {
	session := middleware.GetSession(c)
	if session == nil {
		errx.JSON(c, errx.ErrUnauthorized)
		return
	}
	orgID, err := uuid.Parse(c.Param("orgId"))
	if err != nil {
		errx.JSON(c, errx.New(errx.BadRequest, "invalid organization ID"))
		return
	}
	var req models.CreateLimitIncreaseRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		errx.JSON(c, errx.New(errx.BadRequest, "invalid request body"))
		return
	}
	lr, xerr := h.OrganizationService.SubmitLimitIncreaseRequest(c.Request.Context(), orgID, session.UserID, &req)
	if xerr != nil {
		errx.JSON(c, xerr)
		return
	}
	c.JSON(http.StatusCreated, lr)
}

// ListOrgLimitRequests is GET /v1/organizations/:orgId/limit-requests.
func (h *Handler) ListOrgLimitRequests(c *gin.Context) {
	orgID, err := uuid.Parse(c.Param("orgId"))
	if err != nil {
		errx.JSON(c, errx.New(errx.BadRequest, "invalid organization ID"))
		return
	}
	rows, xerr := h.OrganizationService.ListLimitRequestsForOrg(c.Request.Context(), orgID)
	if xerr != nil {
		errx.JSON(c, xerr)
		return
	}
	c.JSON(http.StatusOK, gin.H{"data": rows})
}

// CancelLimitRequest is DELETE /v1/limit-requests/:id (submitter only).
func (h *Handler) CancelLimitRequest(c *gin.Context) {
	session := middleware.GetSession(c)
	if session == nil {
		errx.JSON(c, errx.ErrUnauthorized)
		return
	}
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		errx.JSON(c, errx.New(errx.BadRequest, "invalid request ID"))
		return
	}
	if xerr := h.OrganizationService.CancelLimitRequest(c.Request.Context(), id, session.UserID); xerr != nil {
		errx.JSON(c, xerr)
		return
	}
	c.Status(http.StatusNoContent)
}

// Admin-facing endpoints under /admin/limit-requests.

// AdminListLimitRequests is GET /admin/limit-requests with the shared faceted
// query params; returns the standard {data, pagination} envelope.
func (h *Handler) AdminListLimitRequests(c *gin.Context) {
	var search models.AdminLimitRequestSearch
	if err := c.ShouldBindQuery(&search); err != nil {
		errx.JSON(c, errx.New(errx.BadRequest, "invalid query parameters"))
		return
	}
	result, xerr := h.OrganizationService.AdminListLimitRequests(c.Request.Context(), &search)
	if xerr != nil {
		errx.JSON(c, xerr)
		return
	}
	c.JSON(http.StatusOK, result)
}

// AdminApproveLimitRequest is POST /admin/limit-requests/:id/approve.
func (h *Handler) AdminApproveLimitRequest(c *gin.Context) {
	adminID := middleware.GetAdminUserID(c)
	if adminID == nil {
		errx.JSON(c, errx.ErrUnauthorized)
		return
	}
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		errx.JSON(c, errx.New(errx.BadRequest, "invalid request ID"))
		return
	}
	var body models.ReviewLimitRequestBody
	_ = c.ShouldBindJSON(&body) // notes are optional

	lr, xerr := h.OrganizationService.ApproveLimitRequest(c.Request.Context(), id, *adminID, body.Notes)
	if xerr != nil {
		errx.JSON(c, xerr)
		return
	}

	h.AdminService.LogAdminAction(
		c.Request.Context(),
		*adminID,
		"approve_limit_request",
		"limit_request",
		&id,
		map[string]any{
			"field":     lr.Field,
			"requested": lr.Requested,
			"notes":     body.Notes,
		},
		c.ClientIP(),
		c.Request.UserAgent(),
	)
	c.JSON(http.StatusOK, lr)
}

// AdminRejectLimitRequest is POST /admin/limit-requests/:id/reject.
func (h *Handler) AdminRejectLimitRequest(c *gin.Context) {
	adminID := middleware.GetAdminUserID(c)
	if adminID == nil {
		errx.JSON(c, errx.ErrUnauthorized)
		return
	}
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		errx.JSON(c, errx.New(errx.BadRequest, "invalid request ID"))
		return
	}
	var body models.ReviewLimitRequestBody
	if err := c.ShouldBindJSON(&body); err != nil || body.Notes == "" {
		errx.JSON(c, errx.New(errx.BadRequest, "review notes are required when rejecting"))
		return
	}

	lr, xerr := h.OrganizationService.RejectLimitRequest(c.Request.Context(), id, *adminID, body.Notes)
	if xerr != nil {
		errx.JSON(c, xerr)
		return
	}

	h.AdminService.LogAdminAction(
		c.Request.Context(),
		*adminID,
		"reject_limit_request",
		"limit_request",
		&id,
		map[string]any{
			"field":     lr.Field,
			"requested": lr.Requested,
			"notes":     body.Notes,
		},
		c.ClientIP(),
		c.Request.UserAgent(),
	)
	c.JSON(http.StatusOK, lr)
}
