package api

import (
	"errors"
	"net/http"

	"github.com/gin-gonic/gin"

	"oci-portal/internal/service"
)

// settingsHandler 处理系统设置（Telegram 通知）相关请求。
type settingsHandler struct {
	svc      *service.SettingService
	notifier *service.Notifier
}

// getTelegram 返回脱敏后的 Telegram 配置，绝不回 token 明文。
//
// @Summary  返回脱敏后的 Telegram 配置，绝不回 token 明文
// @Tags     设置
// @Success  200 {object} service.TelegramView
// @Security BearerAuth
// @Router   /api/v1/settings/telegram [get]
func (h *settingsHandler) getTelegram(c *gin.Context) {
	view, err := h.svc.TelegramView(c.Request.Context())
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, view)
}

// updateTelegramRequest 是保存 Telegram 配置的请求体；
// botToken 缺省表示沿用已存 token，空串表示清除。
type updateTelegramRequest struct {
	Enabled  bool    `json:"enabled"`
	BotToken *string `json:"botToken"`
	ChatID   string  `json:"chatId"`
}

// updateTelegram 保存配置并返回最新脱敏视图。
//
// @Summary  保存配置并返回最新脱敏视图
// @Tags     设置
// @Param    body body updateTelegramRequest true "请求体"
// @Success  200 {object} service.TelegramView
// @Security BearerAuth
// @Router   /api/v1/settings/telegram [put]
func (h *settingsHandler) updateTelegram(c *gin.Context) {
	var req updateTelegramRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	err := h.svc.UpdateTelegram(c.Request.Context(), service.UpdateTelegramInput{
		Enabled:  req.Enabled,
		BotToken: req.BotToken,
		ChatID:   req.ChatID,
	})
	if err != nil {
		respondError(c, err)
		return
	}
	h.getTelegram(c)
}

// testTelegram 用当前已保存配置同步发送一条测试消息。
//
// @Summary  用当前已保存配置同步发送一条测试消息
// @Tags     设置
// @Success  204 "无内容"
// @Security BearerAuth
// @Router   /api/v1/settings/telegram/test [post]
func (h *settingsHandler) testTelegram(c *gin.Context) {
	if err := h.notifier.Test(c.Request.Context()); err != nil {
		respondError(c, err)
		return
	}
	c.Status(http.StatusNoContent)
}

// listNotifyChannels 返回全部通知渠道的脱敏视图(webhook/ntfy/bark/smtp,不含 telegram)。
//
// @Summary  返回全部通知渠道的脱敏视图
// @Tags     设置
// @Success  200 {object} itemsResponse[service.NotifyChannelView]
// @Security BearerAuth
// @Router   /api/v1/settings/notify-channels [get]
func (h *settingsHandler) listNotifyChannels(c *gin.Context) {
	items, err := h.svc.NotifyChannels(c.Request.Context())
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, gin.H{"items": items})
}

// updateNotifyChannelRequest 是保存单渠道配置的请求体;
// secret 承载渠道密文字段(ntfy token / bark device key / smtp 密码),
// 缺省沿用已存值,空串清除。
type updateNotifyChannelRequest struct {
	Enabled      bool    `json:"enabled"`
	URL          string  `json:"url"`
	BodyTemplate string  `json:"bodyTemplate"`
	Server       string  `json:"server"`
	Topic        string  `json:"topic"`
	Host         string  `json:"host"`
	Port         int     `json:"port"`
	Username     string  `json:"username"`
	From         string  `json:"from"`
	To           string  `json:"to"`
	Secret       *string `json:"secret"`
}

// updateNotifyChannel 保存单渠道配置并返回全渠道最新视图;未知类型或校验失败返回 400。
//
// @Summary  保存单渠道配置并返回全渠道最新视图
// @Tags     设置
// @Param    type path string true "渠道类型(webhook/ntfy/bark/smtp)"
// @Param    body body updateNotifyChannelRequest true "请求体"
// @Success  200 {object} itemsResponse[service.NotifyChannelView]
// @Security BearerAuth
// @Router   /api/v1/settings/notify-channels/{type} [put]
func (h *settingsHandler) updateNotifyChannel(c *gin.Context) {
	var req updateNotifyChannelRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	err := h.svc.UpdateNotifyChannel(c.Request.Context(), c.Param("type"), service.UpdateNotifyChannelInput{
		Enabled: req.Enabled, URL: req.URL, BodyTemplate: req.BodyTemplate,
		Server: req.Server, Topic: req.Topic, Host: req.Host, Port: req.Port,
		Username: req.Username, From: req.From, To: req.To, Secret: req.Secret,
	})
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	h.listNotifyChannels(c)
}

// testNotifyChannel 用已保存配置向指定渠道同步发送测试消息。
//
// @Summary  向指定渠道发送测试消息
// @Tags     设置
// @Param    type path string true "渠道类型(webhook/ntfy/bark/smtp)"
// @Success  204 "无内容"
// @Security BearerAuth
// @Router   /api/v1/settings/notify-channels/{type}/test [post]
func (h *settingsHandler) testNotifyChannel(c *gin.Context) {
	if err := h.notifier.SendChannelTest(c.Request.Context(), c.Param("type")); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	c.Status(http.StatusNoContent)
}

// getNotifyEvents 返回全部通知事件开关；键缺省（存量部署）视为开启。
//
// @Summary  返回全部通知事件开关
// @Tags     设置
// @Success  200 {object} service.NotifyEventsView
// @Security BearerAuth
// @Router   /api/v1/settings/notify-events [get]
func (h *settingsHandler) getNotifyEvents(c *gin.Context) {
	view, err := h.svc.NotifyEvents(c.Request.Context())
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, view)
}

// updateNotifyEvents 全量保存五个事件开关并返回最新值；
// 请求体为全量语义，缺字段按 JSON 零值 false 处理。
//
// @Summary  全量保存五个事件开关并返回最新值
// @Tags     设置
// @Param    body body service.NotifyEventsView true "请求体"
// @Success  200 {object} service.NotifyEventsView
// @Security BearerAuth
// @Router   /api/v1/settings/notify-events [put]
func (h *settingsHandler) updateNotifyEvents(c *gin.Context) {
	var req service.NotifyEventsView
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if err := h.svc.UpdateNotifyEvents(c.Request.Context(), req); err != nil {
		respondError(c, err)
		return
	}
	h.getNotifyEvents(c)
}

// listNotifyTemplates 返回全部通知模板(默认模板 + 自定义现值 + 可用变量)。
//
// @Summary  返回全部通知模板
// @Tags     设置
// @Success  200 {object} itemsResponse[service.NotifyTemplateView]
// @Security BearerAuth
// @Router   /api/v1/settings/notify-templates [get]
func (h *settingsHandler) listNotifyTemplates(c *gin.Context) {
	items, err := h.svc.NotifyTemplates(c.Request.Context())
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, gin.H{"items": items})
}

// updateNotifyTemplate 保存单个通知模板;空模板清除自定义(恢复默认)。
//
// @Summary  保存单个通知模板
// @Tags     设置
// @Param    kind path string true "kind"
// @Param    body body object true "请求体(见接口说明)"
// @Success  204 "无内容"
// @Security BearerAuth
// @Router   /api/v1/settings/notify-templates/{kind} [put]
func (h *settingsHandler) updateNotifyTemplate(c *gin.Context) {
	var req struct {
		Template string `json:"template"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if err := h.svc.UpdateNotifyTemplate(c.Request.Context(), c.Param("kind"), req.Template); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	c.Status(http.StatusNoContent)
}

// testNotifyTemplate 用示例变量渲染模板并同步发送测试消息;
// template 非空时按编辑中内容渲染(不落库)。
//
// @Summary  用示例变量渲染模板并同步发送测试消息
// @Tags     设置
// @Param    kind path string true "kind"
// @Param    body body object true "请求体(见接口说明)"
// @Success  204 "无内容"
// @Security BearerAuth
// @Router   /api/v1/settings/notify-templates/{kind}/test [post]
func (h *settingsHandler) testNotifyTemplate(c *gin.Context) {
	var req struct {
		Template string `json:"template"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if err := h.notifier.SendTemplateTest(c.Request.Context(), c.Param("kind"), req.Template); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	c.Status(http.StatusNoContent)
}

// getTaskSettings 返回任务行为设置（抢机熔断阈值），阈值未保存过时为默认值。
//
// @Summary  返回任务行为设置
// @Tags     设置
// @Success  200 {object} service.TaskSettingsView
// @Security BearerAuth
// @Router   /api/v1/settings/task [get]
func (h *settingsHandler) getTaskSettings(c *gin.Context) {
	view, err := h.svc.TaskSettings(c.Request.Context())
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, view)
}

// updateTaskSettings 保存任务行为设置并返回最新值；阈值越界返回 400。
//
// @Summary  保存任务行为设置并返回最新值
// @Tags     设置
// @Param    body body service.TaskSettingsView true "请求体"
// @Success  200 {object} service.TaskSettingsView
// @Security BearerAuth
// @Router   /api/v1/settings/task [put]
func (h *settingsHandler) updateTaskSettings(c *gin.Context) {
	var req service.TaskSettingsView
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if err := h.svc.UpdateTaskSettings(c.Request.Context(), req); err != nil {
		if errors.Is(err, service.ErrInvalidAuthFailLimit) {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		respondError(c, err)
		return
	}
	h.getTaskSettings(c)
}

// getSecurity 返回安全设置(WAF 参数 / 真实IP请求头 / 面板地址),未保存过时为默认值。
//
// @Summary  返回安全设置
// @Tags     设置
// @Success  200 {object} service.SecuritySettings
// @Security BearerAuth
// @Router   /api/v1/settings/security [get]
func (h *settingsHandler) getSecurity(c *gin.Context) {
	view, err := h.svc.Security(c.Request.Context())
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, view)
}

// updateSecurity 保存安全设置并返回最新值;越界或非法返回 400,保存后立即生效。
//
// @Summary  保存安全设置并返回最新值
// @Tags     设置
// @Param    body body service.SecuritySettings true "请求体"
// @Success  200 {object} service.SecuritySettings
// @Security BearerAuth
// @Router   /api/v1/settings/security [put]
func (h *settingsHandler) updateSecurity(c *gin.Context) {
	var req service.SecuritySettings
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if err := h.svc.UpdateSecurity(c.Request.Context(), req); err != nil {
		if errors.Is(err, service.ErrInvalidSecurity) {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		respondError(c, err)
		return
	}
	h.getSecurity(c)
}
