package api

import (
	"errors"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"

	_ "oci-portal/internal/model" // swagger 注解引用

	"oci-portal/internal/service"
)

// logEventHandler 处理回传事件查询与每租户回调地址管理(JWT 组内)。
type logEventHandler struct {
	svc *service.LogEventService
}

// getWebhook 查询配置的回调地址;未生成时 exists 为 false 且不含 secret。
//
// @Summary  查询配置的回调地址
// @Tags     任务与日志回传
// @Param    id path int true "配置 ID"
// @Success  200 {object} logWebhookStatusResponse
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/log-webhook [get]
func (h *logEventHandler) getWebhook(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	info, exists, err := h.svc.SecretInfo(c.Request.Context(), id)
	if err != nil {
		respondError(c, err)
		return
	}
	if !exists {
		c.JSON(http.StatusOK, gin.H{"exists": false})
		return
	}
	c.JSON(http.StatusOK, gin.H{"exists": true, "webhook": info})
}

// ensureWebhook 生成(或幂等返回)配置的回传 secret 与回调路径。
//
// @Summary  生成
// @Tags     任务与日志回传
// @Param    id path int true "配置 ID"
// @Success  200 {object} service.LogWebhookInfo
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/log-webhook [post]
func (h *logEventHandler) ensureWebhook(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	info, err := h.svc.EnsureSecret(c.Request.Context(), id)
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, info)
}

// revokeWebhook 撤销配置的回传 secret,旧回调地址随即失效。
//
// @Summary  撤销配置的回传 secret,旧回调地址随即失效
// @Tags     任务与日志回传
// @Param    id path int true "配置 ID"
// @Success  204 "无内容"
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/log-webhook [delete]
func (h *logEventHandler) revokeWebhook(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	if err := h.svc.RevokeSecret(c.Request.Context(), id); err != nil {
		respondError(c, err)
		return
	}
	c.Status(http.StatusNoContent)
}

// list 分页查询回传事件;cfgId 缺省为全部租户。
//
// @Summary  回传日志事件列表
// @Tags     任务与日志回传
// @Param    configId query int false "按配置过滤"
// @Param    q query string false "关键字"
// @Success  200 {object} pagedResponse[model.LogEvent] "items 与 total"
// @Security BearerAuth
// @Router   /api/v1/log-events [get]
func (h *logEventHandler) list(c *gin.Context) {
	cfgID, _ := strconv.ParseUint(c.Query("cfgId"), 10, 64)
	page, _ := strconv.Atoi(c.Query("page"))
	pageSize, _ := strconv.Atoi(c.Query("pageSize"))
	items, total, err := h.svc.List(c.Request.Context(), service.LogEventQuery{
		CfgID:    uint(cfgID),
		Page:     page,
		PageSize: pageSize,
	})
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, gin.H{"items": items, "total": total})
}

// getRelay 查询 OCI 侧链路状态与关键事件清单。
//
// @Summary  查询 OCI 侧链路状态与关键事件清单
// @Tags     任务与日志回传
// @Param    id path int true "配置 ID"
// @Success  200 {object} service.RelayView
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/log-relay [get]
func (h *logEventHandler) getRelay(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	view, err := h.svc.RelayStatus(c.Request.Context(), id)
	if err != nil {
		respondRelayError(c, err)
		return
	}
	c.JSON(http.StatusOK, view)
}

// setupRelay 一键建立回传链路(P1 引导创建);同步执行,前端以长超时等待。
//
// @Summary  一键建立回传链路
// @Tags     任务与日志回传
// @Param    id path int true "配置 ID"
// @Success  200 {object} service.RelayView
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/log-relay [post]
func (h *logEventHandler) setupRelay(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	view, err := h.svc.SetupRelay(c.Request.Context(), id)
	if err != nil {
		respondRelayError(c, err)
		return
	}
	c.JSON(http.StatusOK, view)
}

// teardownRelay 逆序销毁链路并撤销 secret。
//
// @Summary  逆序销毁链路并撤销 secret
// @Tags     任务与日志回传
// @Param    id path int true "配置 ID"
// @Success  204 "无内容"
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/log-relay [delete]
func (h *logEventHandler) teardownRelay(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	if err := h.svc.TeardownRelay(c.Request.Context(), id); err != nil {
		respondRelayError(c, err)
		return
	}
	c.Status(http.StatusNoContent)
}

// respondRelayError 在通用映射之上补充引导创建专属错误:依赖未配置映射 409。
func respondRelayError(c *gin.Context, err error) {
	if errors.Is(err, service.ErrRelayNotConfigured) {
		c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
		return
	}
	respondError(c, err)
}
