package api

import (
	"net/http"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/alertstore/pkg/alert"
	"github.com/tidbcloud/alertstore/pkg/metrics"
	"github.com/tidbcloud/alertstore/pkg/webhook"
)

// webhookAlertmanager handles authenticated Alertmanager webhook deliveries
// from both the in-cluster and public gateway routes.
// A 5xx response makes alertmanager retry the payload; processing is
// idempotent so retries are safe.
func (s *Server) webhookAlertmanager(c *gin.Context) {
	var payload webhook.AlertmanagerPayload
	if err := c.ShouldBindJSON(&payload); err != nil {
		metrics.WebhookRequests.WithLabelValues("alertmanager", "bad_request").Inc()
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := s.webhookHandler.HandleAlertmanager(c.Request.Context(), &payload); err != nil {
		metrics.WebhookRequests.WithLabelValues("alertmanager", "error").Inc()
		s.logger.Error("handle alertmanager webhook", "err", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	metrics.WebhookRequests.WithLabelValues("alertmanager", "ok").Inc()
	c.JSON(http.StatusOK, gin.H{"status": "ok"})
}

// webhookJira handles POST /alertstore/webhooks/jira
// Transitional: maps Jira status changes to alert operations.
func (s *Server) webhookJira(c *gin.Context) {
	var body struct {
		WebhookEvent string `json:"webhookEvent"`
		Issue        struct {
			Key    string `json:"key"`
			Fields struct {
				Status struct {
					Name string `json:"name"`
				} `json:"status"`
				Assignee struct {
					EmailAddress string `json:"emailAddress"`
				} `json:"assignee"`
			} `json:"fields"`
		} `json:"issue"`
		User struct {
			EmailAddress string `json:"emailAddress"`
		} `json:"user"`
		Changelog struct {
			Items []struct {
				Field      string `json:"field"`
				FromString string `json:"fromString"`
				ToString   string `json:"toString"`
			} `json:"items"`
		} `json:"changelog"`
	}

	if err := c.ShouldBindJSON(&body); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	ctx := c.Request.Context()
	issueKey := body.Issue.Key
	user := body.User.EmailAddress

	a, err := s.alertStore.FindByExternalIssueKey(ctx, issueKey)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if a == nil {
		c.JSON(http.StatusOK, gin.H{"status": "ignored", "reason": "no matching alert"})
		return
	}

	for _, item := range body.Changelog.Items {
		switch item.Field {
		case "status":
			switch item.ToString {
			case "In Progress":
				_ = s.alertService.Ack(ctx, a.ID, user, alert.SourceIssueTracker)
			case "Done", "Resolved", "Closed":
				// Preserve the same open -> acked -> resolved lifecycle when
				// Jira moves directly to a terminal state. Jira does not carry
				// a verdict, so this assumes the common case: someone closing
				// an issue acted on it.
				_ = s.alertService.Ack(ctx, a.ID, user, alert.SourceIssueTracker)
				_ = s.alertService.Resolve(ctx, a.ID, user, alert.SourceIssueTracker, alert.ResolutionHandled, "closed from Jira")
			}
		case "assignee":
			assignee := body.Issue.Fields.Assignee.EmailAddress
			if err := s.alertService.Assign(ctx, a.ID, user, alert.SourceIssueTracker, assignee, "jira_assignee_change"); err == nil {
				s.announceReassignment(ctx, a.ID, user, assignee, "jira_assignee_change")
			}
		}
	}

	c.JSON(http.StatusOK, gin.H{"status": "ok"})
}
