package service

import (
	"html"
	"regexp"
	"strings"
	"time"
)

// notifyTplDef 描述一类通知的模板元数据与示例变量(测试发送用)。
// 所有模板额外提供公共变量 {{time}}(发送时刻)。
type notifyTplDef struct {
	Label   string
	Default string
	Vars    []string
	Sample  map[string]string
}

// notifyTplOrder 是模板列表的稳定输出顺序(与通知管理事件一致)。
var notifyTplOrder = []string{
	"task_fail", "task_recover", "snatch_success", "tenant_dead", "task_stop",
	"login_lock", "model_deprecated",
	"log_event_instance", "log_event_identity", "log_event_policy", "log_event_region", "log_event_login",
}

var notifyTplDefs = map[string]notifyTplDef{
	"task_fail": {
		Label:   "任务失败",
		Default: "❌ 任务失败:{{task_name}}\n{{error}}",
		Vars:    []string{"task_name", "error"},
		Sample:  map[string]string{"task_name": "示例测活任务", "error": "鉴权失败: 401 NotAuthenticated"},
	},
	"task_recover": {
		Label:   "任务恢复",
		Default: "✅ 任务恢复:{{task_name}}",
		Vars:    []string{"task_name"},
		Sample:  map[string]string{"task_name": "示例测活任务"},
	},
	"snatch_success": {
		Label:   "抢机成功",
		Default: "🎉 抢机成功:{{task_name}}\n租户:{{tenant}}\n区域:{{region}}\n类型:{{shape}}\n配置:{{spec}}\n镜像:{{image}}\nIP:{{ip}}\n密码:{{root_password}}",
		Vars:    []string{"task_name", "tenant", "region", "shape", "spec", "image", "ip", "root_password", "message"},
		Sample: map[string]string{
			"task_name": "示例抢机任务", "tenant": "免费01", "region": "Japan Central (Osaka)",
			"shape": "VM.Standard.A1.Flex", "spec": "4C/24G", "image": "Canonical-Ubuntu-24.04-aarch64-2025.05.20-0",
			"ip": "129.150.32.10", "root_password": "Xy3#kP9m-2Qw@7Zn", "message": "created 1: ocid1.instance…",
		},
	},
	"tenant_dead": {
		Label:   "租户失联",
		Default: "⚠️ 租户失联:{{tenants}}",
		Vars:    []string{"tenants"},
		Sample:  map[string]string{"tenants": "免费01、免费02"},
	},
	"task_stop": {
		Label:   "任务停止",
		Default: "⛔ 任务已停止:{{task_name}}\n{{error}}",
		Vars:    []string{"task_name", "error"},
		Sample:  map[string]string{"task_name": "示例抢机任务", "error": "连续鉴权失败 5 次,任务熔断"},
	},
	"login_lock": {
		Label:   "登录锁定",
		Default: "🚫 登录锁定:用户 {{username}}(来自 {{ip}})连续失败 {{fail_count}} 次,已锁定 {{lock_minutes}} 分钟",
		Vars:    []string{"username", "ip", "fail_count", "lock_minutes"},
		Sample:  map[string]string{"username": "admin", "ip": "203.0.113.8", "fail_count": "5", "lock_minutes": "15"},
	},
	"model_deprecated": {
		Label:   "模型弃用预警",
		Default: "⚠️ AI 网关:以下在池模型即将被 OCI 退役或弃用(退役后无法调用,弃用仅为预告)\n{{models}}",
		Vars:    []string{"models"},
		Sample:  map[string]string{"models": "meta.llama-3.1-70b-instruct(2026-08-01 退役,届时无法调用)"},
	},
	"log_event_instance": {
		Label:   "实例生命周期",
		Default: "☁️ 云端事件:{{tenant}} {{event}} {{resource}} · {{outcome}}\n操作者 {{actor}} · 来源 {{ip}}{{detail}}",
		Vars:    []string{"tenant", "event", "resource", "actor", "ip", "outcome", "detail"},
		Sample: map[string]string{"tenant": "免费01", "event": "TerminateInstance", "resource": "web-server-1",
			"actor": "demo@example.com", "ip": "203.0.113.8", "outcome": "成功", "detail": ""},
	},
	"log_event_identity": {
		Label:   "用户与凭据",
		Default: "☁️ 云端事件:{{tenant}} {{event}} {{resource}} · {{outcome}}\n操作者 {{actor}} · 来源 {{ip}}{{detail}}",
		Vars:    []string{"tenant", "event", "resource", "actor", "ip", "outcome", "detail"},
		Sample: map[string]string{"tenant": "免费01", "event": "CreateApiKey", "resource": "user/demo",
			"actor": "admin@example.com", "ip": "203.0.113.8", "outcome": "成功", "detail": ""},
	},
	"log_event_policy": {
		Label:   "策略变更",
		Default: "☁️ 云端事件:{{tenant}} {{event}} {{resource}} · {{outcome}}\n操作者 {{actor}} · 来源 {{ip}}{{detail}}",
		Vars:    []string{"tenant", "event", "resource", "actor", "ip", "outcome", "detail"},
		Sample: map[string]string{"tenant": "免费01", "event": "CreatePolicy", "resource": "admin-policy",
			"actor": "admin@example.com", "ip": "203.0.113.8", "outcome": "成功",
			"detail": "\n允许 Service Connector 发布到 ONS Topic"},
	},
	"log_event_region": {
		Label:   "区域订阅",
		Default: "☁️ 云端事件:{{tenant}} {{event}} {{resource}} · {{outcome}}\n操作者 {{actor}} · 来源 {{ip}}{{detail}}",
		Vars:    []string{"tenant", "event", "resource", "actor", "ip", "outcome", "detail"},
		Sample: map[string]string{"tenant": "免费01", "event": "CreateRegionSubscription", "resource": "ap-osaka-1",
			"actor": "admin@example.com", "ip": "203.0.113.8", "outcome": "成功", "detail": ""},
	},
	"log_event_login": {
		Label:   "控制台登录",
		Default: "☁️ 云端事件:{{tenant}} {{event}} · {{outcome}}\n用户 {{actor}} · 登录 IP {{ip}}{{detail}}",
		Vars:    []string{"tenant", "event", "resource", "actor", "ip", "outcome", "detail"},
		Sample: map[string]string{"tenant": "免费01", "event": "InteractiveLogin", "resource": "—",
			"actor": "demo@example.com", "ip": "155.117.82.111", "outcome": "失败",
			"detail": "\nAuthentication failure : You entered an incorrect user name or password."},
	},
}

var notifyVarPattern = regexp.MustCompile(`\{\{(\w+)\}\}`)

// renderNotifyTemplate 用 {{var}} 占位符渲染模板;未知变量原样保留,
// 公共变量 time 自动注入(调用方未提供时)。
func renderNotifyTemplate(tpl string, vars map[string]string) string {
	if _, ok := vars["time"]; !ok {
		if vars == nil {
			vars = map[string]string{}
		}
		vars["time"] = time.Now().Format("2006-01-02 15:04:05")
	}
	return notifyVarPattern.ReplaceAllStringFunc(tpl, func(m string) string {
		if v, ok := vars[m[2:len(m)-2]]; ok {
			return v
		}
		return m
	})
}

var (
	notifyMdPre    = regexp.MustCompile("(?s)```\n?(.+?)\n?```")
	notifyMdCode   = regexp.MustCompile("`([^`\n]+)`")
	notifyMdBold   = regexp.MustCompile(`\*([^*\n]+)\*`)
	notifyMdItalic = regexp.MustCompile(`_([^_\n]+)_`)
)

// mdToTelegramHTML 把轻量 Markdown(*粗体* / _斜体_ / `代码` / ```代码块```)转为
// Telegram HTML;先整体 HTML 转义,未闭合标记原样保留,天然不产生残缺标签。
func mdToTelegramHTML(text string) string {
	out := html.EscapeString(text)
	out = notifyMdPre.ReplaceAllString(out, "<pre>$1</pre>")
	out = notifyMdCode.ReplaceAllString(out, "<code>$1</code>")
	out = notifyMdBold.ReplaceAllString(out, "<b>$1</b>")
	out = notifyMdItalic.ReplaceAllString(out, "<i>$1</i>")
	return out
}

// NotifyTemplateView 是模板设置接口的列表项。
type NotifyTemplateView struct {
	Kind            string   `json:"kind"`
	Label           string   `json:"label"`
	Vars            []string `json:"vars"`
	DefaultTemplate string   `json:"defaultTemplate"`
	// Template 是自定义模板;空串表示未自定义(按默认发送)
	Template string `json:"template"`
}

// notifyTplKey 是 kind 对应的 Setting 键。
func notifyTplKey(kind string) string { return "notify_tpl_" + kind }

// notifyTplValid 报告 kind 是否为已知通知类型。
func notifyTplValid(kind string) bool {
	_, ok := notifyTplDefs[kind]
	return ok
}

// notifyTplText 返回 kind 生效模板:自定义非空用自定义,否则默认。
func notifyTplText(custom, kind string) string {
	if strings.TrimSpace(custom) != "" {
		return custom
	}
	return notifyTplDefs[kind].Default
}

// notifyTplLabel 返回 kind 的显示名,供渠道消息标题(ntfy/bark/邮件主题)使用。
func notifyTplLabel(kind string) string {
	if def, ok := notifyTplDefs[kind]; ok {
		return def.Label
	}
	return "oci-portal 通知"
}
