// Package notification 提供站内通知模板注册、渲染和 PostgreSQL 持久化 Adapter。
package notification

import (
	"bytes"
	"errors"
	"regexp"
	"strings"
	"text/template"

	"github.com/break/junhong_cmp_fiber/pkg/constants"
)

var (
	htmlTagPattern       = regexp.MustCompile(`(?i)<\s*/?\s*[a-z][^>]*>`)
	sensitiveTextPattern = regexp.MustCompile(`(?i)(password|operation_password|token|secret|credential|media_id|密码|令牌|密钥)\s*[:=：]\s*\S+`)
	longURLPattern       = regexp.MustCompile(`(?i)https?://\S+`)
)

// Definition 定义一个受控通知类型的类别、级别、模板和允许资源引用。
type Definition struct {
	Type            string
	Category        string
	Severity        string
	TitleTemplate   string
	BodyTemplate    string
	TemplateFields  map[string]struct{}
	RecipientKinds  map[string]struct{}
	AllowedRefTypes map[string]struct{}
}

// Rendered 是模板渲染后的纯文本快照。
type Rendered struct {
	Category string
	Type     string
	Severity string
	Title    string
	Body     string
}

// Registry 保存代码内受控通知类型注册关系。
type Registry struct {
	definitions map[string]Definition
}

// NewRegistry 创建内置受控通知类型注册表。
func NewRegistry() *Registry {
	return &Registry{definitions: map[string]Definition{
		constants.NotificationTypeSystemNotice: {
			Type: constants.NotificationTypeSystemNotice, Category: constants.NotificationCategorySystem,
			Severity:       constants.NotificationSeverityInfo,
			TitleTemplate:  "系统通知",
			BodyTemplate:   "有一项系统事项需要处理，请进入对应页面查看。",
			TemplateFields: map[string]struct{}{},
			RecipientKinds: map[string]struct{}{constants.NotificationRecipientKindAccount: {}},
			AllowedRefTypes: map[string]struct{}{
				constants.NotificationRefTypeSystemConfig:   {},
				constants.NotificationRefTypeIntegrationLog: {},
			},
		},
		constants.NotificationTypePackageExpiring: {
			Type: constants.NotificationTypePackageExpiring, Category: constants.NotificationCategoryExpiry,
			Severity:       constants.NotificationSeverityWarning,
			TitleTemplate:  "套餐即将到期",
			BodyTemplate:   "您的套餐即将到期，请及时查看并处理。",
			TemplateFields: map[string]struct{}{},
			RecipientKinds: map[string]struct{}{constants.NotificationRecipientKindPersonalCustomer: {}},
			AllowedRefTypes: map[string]struct{}{
				constants.NotificationRefTypePackage: {},
				constants.NotificationRefTypeAsset:   {},
			},
		},
		constants.NotificationTypeExchangeShippingCreated: {
			Type: constants.NotificationTypeExchangeShippingCreated, Category: constants.NotificationCategorySystem,
			Severity:       constants.NotificationSeverityInfo,
			TitleTemplate:  "换货申请待处理",
			BodyTemplate:   "您有一条物流换货申请待处理，请及时填写收货信息。",
			TemplateFields: map[string]struct{}{},
			RecipientKinds: map[string]struct{}{constants.NotificationRecipientKindPersonalCustomer: {}},
			AllowedRefTypes: map[string]struct{}{
				constants.NotificationRefTypeAsset: {},
			},
		},
		constants.NotificationTypeAgentMainWalletLowBalance: {
			Type: constants.NotificationTypeAgentMainWalletLowBalance, Category: constants.NotificationCategorySystem,
			Severity:       constants.NotificationSeverityWarning,
			TitleTemplate:  "店铺主钱包余额不足",
			BodyTemplate:   "店铺主钱包余额低于 100 元，请及时关注。",
			TemplateFields: map[string]struct{}{},
			RecipientKinds: map[string]struct{}{constants.NotificationRecipientKindAccount: {}},
			AllowedRefTypes: map[string]struct{}{
				constants.NotificationRefTypeShopFund: {},
			},
		},
	}}
}

// Render 校验注册类型、模板字段、资源引用与敏感内容后生成纯文本快照。
func (r *Registry) Render(notificationType string, data map[string]string, refType, recipientKind string) (Rendered, error) {
	definition, exists := r.definitions[notificationType]
	if !exists {
		return Rendered{}, errors.New("通知类型未注册")
	}
	if _, allowed := definition.RecipientKinds[recipientKind]; !allowed {
		return Rendered{}, errors.New("通知类型未向当前接收人开放")
	}
	if err := validateTemplateData(data, definition.TemplateFields); err != nil {
		return Rendered{}, err
	}
	if refType != "" {
		if _, allowed := definition.AllowedRefTypes[refType]; !allowed {
			return Rendered{}, errors.New("通知资源类型未注册")
		}
	}
	title, err := executeTemplate("通知标题", definition.TitleTemplate, data)
	if err != nil {
		return Rendered{}, err
	}
	body, err := executeTemplate("通知正文", definition.BodyTemplate, data)
	if err != nil {
		return Rendered{}, err
	}
	if title == "" || body == "" {
		return Rendered{}, errors.New("通知模板字段为空")
	}
	if len([]rune(title)) > constants.NotificationMaxTitleLength {
		return Rendered{}, errors.New("通知标题超过长度限制")
	}
	if len([]rune(body)) > constants.NotificationMaxBodyLength {
		return Rendered{}, errors.New("通知正文超过长度限制")
	}
	if htmlTagPattern.MatchString(title) || htmlTagPattern.MatchString(body) {
		return Rendered{}, errors.New("通知正文禁止包含 HTML")
	}
	if sensitiveTextPattern.MatchString(title) || sensitiveTextPattern.MatchString(body) || longURLPattern.MatchString(title) || longURLPattern.MatchString(body) {
		return Rendered{}, errors.New("通知正文包含禁止的敏感内容")
	}
	return Rendered{
		Category: definition.Category, Type: definition.Type, Severity: definition.Severity,
		Title: title, Body: body,
	}, nil
}

func executeTemplate(name, source string, data map[string]string) (string, error) {
	tmpl, err := template.New(name).Option("missingkey=error").Parse(source)
	if err != nil {
		return "", err
	}
	var buffer bytes.Buffer
	if err := tmpl.Execute(&buffer, data); err != nil {
		return "", errors.New("通知模板字段缺失")
	}
	return strings.TrimSpace(buffer.String()), nil
}

func validateTemplateData(data map[string]string, fields map[string]struct{}) error {
	if data == nil && len(fields) > 0 {
		return errors.New("通知模板数据不能为空")
	}
	for key := range data {
		normalized := strings.ToLower(strings.TrimSpace(key))
		switch normalized {
		case "password", "operation_password", "token", "secret", "credential", "id_card", "callback", "media_id", "url":
			return errors.New("通知模板数据包含禁止字段")
		}
		if _, allowed := fields[normalized]; !allowed {
			return errors.New("通知模板数据包含未注册字段")
		}
	}
	for field := range fields {
		if strings.TrimSpace(data[field]) == "" {
			return errors.New("通知模板必填字段缺失")
		}
	}
	return nil
}
