package certificate

import (
	"context"
	"encoding/json"
	"strconv"
	"strings"

	"github.com/usual2970/certimate/internal/app"
	"github.com/usual2970/certimate/internal/domain"
	"github.com/usual2970/certimate/internal/notify"
	"github.com/usual2970/certimate/internal/repository"
)

const (
	defaultExpireSubject = "您有 ${COUNT} 张证书即将过期"
	defaultExpireMessage = "有 ${COUNT} 张证书即将过期,域名分别为 ${DOMAINS},请保持关注!"
)

type CertificateRepository interface {
	ListExpireSoon(ctx context.Context) ([]domain.Certificate, error)
}

type certificateService struct {
	repo CertificateRepository
}

func NewCertificateService(repo CertificateRepository) *certificateService {
	return &certificateService{
		repo: repo,
	}
}

func (s *certificateService) InitSchedule(ctx context.Context) error {
	scheduler := app.GetScheduler()
	err := scheduler.Add("certificate", "0 0 * * *", func() {
		certs, err := s.repo.ListExpireSoon(context.Background())
		if err != nil {
			app.GetLogger().Error("failed to get expire soon certificate", "err", err)
			return
		}

		notification := buildExpireSoonNotification(certs)
		if notification == nil {
			return
		}

		if err := notify.SendToAllChannels(notification.Subject, notification.Message); err != nil {
			app.GetLogger().Error("failed to send expire soon certificate", "err", err)
		}
	})
	if err != nil {
		app.GetLogger().Error("failed to add schedule", "err", err)
		return err
	}
	scheduler.Start()
	app.GetLogger().Info("certificate schedule started")
	return nil
}

type certificateNotification struct {
	Subject string `json:"subject"`
	Message string `json:"message"`
}

func buildExpireSoonNotification(records []domain.Certificate) *certificateNotification {
	if len(records) == 0 {
		return nil
	}

	subject := defaultExpireSubject
	message := defaultExpireMessage

	// 查询模板信息
	settingRepo := repository.NewSettingsRepository()
	setting, err := settingRepo.GetByName(context.Background(), "notifyTemplates")
	if err == nil {
		var templates *domain.NotifyTemplatesSettingsContent
		json.Unmarshal([]byte(setting.Content), &templates)

		if templates != nil && len(templates.NotifyTemplates) > 0 {
			subject = templates.NotifyTemplates[0].Subject
			message = templates.NotifyTemplates[0].Message
		}
	}

	// 替换变量
	count := len(records)
	domains := make([]string, count)
	for i, record := range records {
		domains[i] = record.SubjectAltNames
	}
	countStr := strconv.Itoa(count)
	domainStr := strings.Join(domains, ";")
	subject = strings.ReplaceAll(subject, "${COUNT}", countStr)
	subject = strings.ReplaceAll(subject, "${DOMAINS}", domainStr)
	message = strings.ReplaceAll(message, "${COUNT}", countStr)
	message = strings.ReplaceAll(message, "${DOMAINS}", domainStr)

	// 返回消息
	return &certificateNotification{
		Subject: subject,
		Message: message,
	}
}