package handler

import (
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"

	"github.com/warmbly/warmbly/internal/api/middleware"
	"github.com/warmbly/warmbly/internal/errx"
	"github.com/warmbly/warmbly/internal/models"
)

// verifyEmailRequest is the optional JSON body for VerifyEmail. The address may
// also be passed as the `email` query param; the body takes precedence.
type verifyEmailRequest struct {
	Email string `json:"email"`
}

// VerifyEmail verifies a single email address on demand through whichever
// verifier the workspace uses (its connected provider, else the built-in
// check) and returns the emailverify.Result. Nothing is stored.
//
// Control-plane only: the SMTP RCPT probe behind the built-in check runs from
// the backend (a non-sending IP), never a worker. See internal/pkg/emailverify.
func (h *Handler) VerifyEmail(c *gin.Context) {
	if _, err := middleware.GetUserUUID(c); err != nil {
		errx.JSON(c, errx.ErrUnauthorized)
		return
	}
	if h.EmailVerifyService == nil {
		errx.JSON(c, errx.InternalError())
		return
	}
	orgID, ok := requireOrgID(c)
	if !ok {
		return
	}

	var req verifyEmailRequest
	// Body is optional; ignore a bind error and fall back to the query param.
	_ = c.ShouldBindJSON(&req)
	email := strings.TrimSpace(req.Email)
	if email == "" {
		email = strings.TrimSpace(c.Query("email"))
	}
	if email == "" {
		errx.JSON(c, errx.ErrEmail)
		return
	}

	res := h.EmailVerifyService.VerifyAddress(c.Request.Context(), orgID, email)
	c.JSON(http.StatusOK, res)
}

// GetContactVerification reports which verifier the workspace uses, its
// remaining credits, and the contacts by verdict.
// GET /contacts/verification
func (h *Handler) GetContactVerification(c *gin.Context) {
	if h.EmailVerifyService == nil {
		errx.JSON(c, errx.InternalError())
		return
	}
	orgID, ok := requireOrgID(c)
	if !ok {
		return
	}
	out, xerr := h.EmailVerifyService.Overview(c.Request.Context(), orgID)
	if xerr != nil {
		errx.JSON(c, xerr)
		return
	}
	c.JSON(http.StatusOK, out)
}

// RequestContactVerification queues a re-check of the listed contacts, or
// records a manual verdict on them.
// POST /contacts/verification
func (h *Handler) RequestContactVerification(c *gin.Context) {
	if h.EmailVerifyService == nil {
		errx.JSON(c, errx.InternalError())
		return
	}
	orgID, ok := requireOrgID(c)
	if !ok {
		return
	}
	var req models.ContactVerificationRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		errx.JSON(c, errx.ErrInvalid)
		return
	}
	if len(req.Contacts) > maxBulkOperationSize {
		errx.JSON(c, errx.NewWithIdentifier(errx.BadRequest, "too_many_contacts",
			"too many contacts, maximum is "+itoa(maxBulkOperationSize)+" per request"))
		return
	}
	resp, xerr := h.EmailVerifyService.Request(c.Request.Context(), orgID, req)
	if xerr != nil {
		errx.JSON(c, xerr)
		return
	}
	// The audit spine refreshes every teammate's contact lists; verdicts
	// then land live as the background pass records them.
	h.auditOrg(c, models.AuditActionUpdate, models.AuditEntityContact, nil, nil, map[string]string{
		"verification": req.Action, "count": itoa(resp.Affected),
	})
	c.JSON(http.StatusOK, resp)
}
