package handler

import (
	"errors"
	"net/http"

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

// Website tracking settings (JWT only, MANAGE_SETTINGS).

func (h *Handler) GetWebsiteTrackingSettings(c *gin.Context) {
	orgID := middleware.GetOrganizationID(c)
	if orgID == nil {
		errx.JSON(c, errx.New(errx.BadRequest, "no organization selected"))
		return
	}
	settings, xerr := h.WebsiteTrackingService.GetSettings(c.Request.Context(), *orgID)
	if xerr != nil {
		errx.JSON(c, xerr)
		return
	}
	c.JSON(http.StatusOK, settings)
}

func (h *Handler) UpdateWebsiteTrackingSettings(c *gin.Context) {
	orgID := middleware.GetOrganizationID(c)
	if orgID == nil {
		errx.JSON(c, errx.New(errx.BadRequest, "no organization selected"))
		return
	}
	userID, err := middleware.GetUserUUID(c)
	if err != nil {
		errx.JSON(c, errx.New(errx.BadRequest, "invalid user id"))
		return
	}
	var req models.UpdateWebsiteTrackingSettingsRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		errx.JSON(c, errx.ErrInvalid)
		return
	}
	settings, xerr := h.WebsiteTrackingService.UpdateSettings(c.Request.Context(), *orgID, userID, &req)
	if xerr != nil {
		errx.JSON(c, xerr)
		return
	}
	h.auditOrg(c, models.AuditActionUpdate, models.AuditEntitySettings, nil, nil, map[string]string{
		"scope": "website_tracking",
	})
	c.JSON(http.StatusOK, settings)
}

// RotateWebsiteTrackingKey issues a new site key; the old one stops at once.
func (h *Handler) RotateWebsiteTrackingKey(c *gin.Context) {
	orgID := middleware.GetOrganizationID(c)
	if orgID == nil {
		errx.JSON(c, errx.New(errx.BadRequest, "no organization selected"))
		return
	}
	userID, err := middleware.GetUserUUID(c)
	if err != nil {
		errx.JSON(c, errx.New(errx.BadRequest, "invalid user id"))
		return
	}
	settings, xerr := h.WebsiteTrackingService.RotateSiteKey(c.Request.Context(), *orgID, userID)
	if xerr != nil {
		errx.JSON(c, xerr)
		return
	}
	h.auditOrg(c, models.AuditActionUpdate, models.AuditEntitySettings, nil, nil, map[string]string{
		"scope":  "website_tracking",
		"action": "rotate_site_key",
	})
	c.JSON(http.StatusOK, settings)
}

// InternalIngestPageHit receives a page view from the tracking service.
//
//	POST /api/v1/internal/page-hits
//	  -> 204 accepted or quietly rejected | 200 {"new_visitor_key":...}
//	  -> 400 malformed | 404 unknown site key (cached negatively at the edge)
func (h *Handler) InternalIngestPageHit(c *gin.Context) {
	var req models.WebsiteHitRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid body"})
		return
	}
	result, err := h.WebsiteTrackingService.Ingest(c.Request.Context(), &req)
	switch {
	case errors.Is(err, websitetracking.ErrMalformed):
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid hit"})
	case errors.Is(err, websitetracking.ErrUnknownSite):
		c.Status(http.StatusNotFound)
	case errors.Is(err, websitetracking.ErrRejected):
		c.Status(http.StatusNoContent)
	case err != nil:
		c.JSON(http.StatusInternalServerError, gin.H{"error": "ingest failed"})
	case result != nil && result.NewVisitorKey != "":
		c.JSON(http.StatusOK, result)
	default:
		c.Status(http.StatusNoContent)
	}
}

// websiteIdentifyForLink: may this click destination carry the identification ticket?
func (h *Handler) websiteIdentifyForLink(c *gin.Context, campaignID uuid.UUID, destination string) bool {
	if h.WebsiteTrackingService == nil {
		return false
	}
	return h.WebsiteTrackingService.ShouldIdentify(c.Request.Context(), campaignID, destination)
}
