package emailLogic

import (
	"bytes"
	"context"
	"encoding/json"
	"strings"
	"text/template"
	"time"

	"github.com/perfect-panel/server/pkg/logger"

	"github.com/hibiken/asynq"
	"github.com/perfect-panel/server/internal/model/log"
	"github.com/perfect-panel/server/internal/svc"
	"github.com/perfect-panel/server/pkg/constant"
	"github.com/perfect-panel/server/pkg/email"
	"github.com/perfect-panel/server/queue/types"
)

type SendEmailLogic struct {
	svcCtx *svc.ServiceContext
}

func NewSendEmailLogic(svcCtx *svc.ServiceContext) *SendEmailLogic {
	return &SendEmailLogic{
		svcCtx: svcCtx,
	}
}
func (l *SendEmailLogic) ProcessTask(ctx context.Context, task *asynq.Task) error {
	var payload types.SendEmailPayload
	if err := json.Unmarshal(task.Payload(), &payload); err != nil {
		logger.WithContext(ctx).Error("[SendEmailLogic] Unmarshal payload failed",
			logger.Field("error", err.Error()),
			logger.Field("payload", task.Payload()),
		)
		return nil
	}
	messageLog := log.Message{
		Platform: l.svcCtx.Config.Email.Platform,
		To:       payload.Email,
		Subject:  payload.Subject,
		Content:  payload.Content,
	}
	sender, err := email.NewSender(l.svcCtx.Config.Email.Platform, l.svcCtx.Config.Email.PlatformConfig, l.svcCtx.Config.Site.SiteName)
	if err != nil {
		logger.WithContext(ctx).Error("[SendEmailLogic] NewSender failed", logger.Field("error", err.Error()))
		return nil
	}
	var content string
	switch payload.Type {
	case types.EmailTypeVerify:
		if t, ok := payload.Content["Type"].(float64); ok {
			payload.Content["Type"] = int(t)
		} else if t, ok := payload.Content["Type"].(int); ok {
			payload.Content["Type"] = t
		}

		typeVal, _ := payload.Content["Type"].(int)
		scene := resolveVerifyScene(payload.Scene, typeVal)
		tplStr := selectVerifyTemplate(l.svcCtx.Config.Email.VerifyEmailTemplates, l.svcCtx.Config.Email.VerifyEmailTemplate, scene)

		tpl, _ := template.New("verify").Parse(tplStr)
		var result bytes.Buffer

		err = tpl.Execute(&result, payload.Content)
		if err != nil {
			logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed",
				logger.Field("error", err.Error()),
				logger.Field("data", payload.Content),
			)
			return nil
		}
		content = result.String()
	case types.EmailTypeDeleteAccount:
		tplStr := l.svcCtx.Config.Email.DeleteAccountEmailTemplate
		if tplStr == "" {
			tplStr = email.DefaultDeleteAccountEmailTemplate
		}
		tpl, _ := template.New("delete_account").Parse(tplStr)
		var result bytes.Buffer
		err = tpl.Execute(&result, payload.Content)
		if err != nil {
			logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed",
				logger.Field("error", err.Error()),
				logger.Field("template", l.svcCtx.Config.Email.DeleteAccountEmailTemplate),
				logger.Field("data", payload.Content),
			)
			return nil
		}
		content = result.String()
	case types.EmailTypeMaintenance:
		tplStr := l.svcCtx.Config.Email.MaintenanceEmailTemplate
		if tplStr == "" {
			tplStr = email.DefaultMaintenanceEmailTemplate
		}
		tpl, _ := template.New("maintenance").Parse(tplStr)
		var result bytes.Buffer
		err = tpl.Execute(&result, payload.Content)
		if err != nil {
			logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed",
				logger.Field("error", err.Error()),
				logger.Field("template", l.svcCtx.Config.Email.MaintenanceEmailTemplate),
				logger.Field("data", payload.Content),
			)
			return nil
		}
		content = result.String()
	case types.EmailTypeExpiration:
		tplStr := l.svcCtx.Config.Email.ExpirationEmailTemplate
		if tplStr == "" {
			tplStr = email.DefaultExpirationEmailTemplate
		}
		tpl, _ := template.New("expiration").Parse(tplStr)
		var result bytes.Buffer
		err = tpl.Execute(&result, payload.Content)
		if err != nil {
			logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed",
				logger.Field("error", err.Error()),
				logger.Field("template", l.svcCtx.Config.Email.ExpirationEmailTemplate),
				logger.Field("data", payload.Content),
			)
			return nil
		}
		content = result.String()
	case types.EmailTypeTrafficExceed:
		tplStr := l.svcCtx.Config.Email.TrafficExceedEmailTemplate
		if tplStr == "" {
			tplStr = email.DefaultTrafficExceedEmailTemplate
		}
		tpl, _ := template.New("traffic_exceed").Parse(tplStr)
		var result bytes.Buffer
		err = tpl.Execute(&result, payload.Content)
		if err != nil {
			logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed",
				logger.Field("error", err.Error()),
				logger.Field("template", l.svcCtx.Config.Email.TrafficExceedEmailTemplate),
				logger.Field("data", payload.Content),
			)
			return nil
		}
		content = result.String()
	case types.EmailTypeCustom:
		if payload.Content == nil {
			logger.WithContext(ctx).Error("[SendEmailLogic] Custom email content is empty",
				logger.Field("payload", payload),
			)
			return nil
		}
		if tpl, ok := payload.Content["content"].(string); !ok {
			logger.WithContext(ctx).Error("[SendEmailLogic] Custom email content is not a string",
				logger.Field("payload", payload),
			)
			return nil
		} else {
			content = tpl
		}
	default:
		logger.WithContext(ctx).Error("[SendEmailLogic] Unsupported email type",
			logger.Field("type", payload.Type),
			logger.Field("payload", payload),
		)
		return nil
	}

	err = sender.Send([]string{payload.Email}, payload.Subject, content)
	if err != nil {
		logger.WithContext(ctx).Error("[SendEmailLogic] Send email failed", logger.Field("error", err.Error()))
		return nil
	}
	messageLog.Status = 1
	emailLog, err := messageLog.Marshal()
	if err != nil {
		logger.WithContext(ctx).Error("[SendEmailLogic] Marshal message log failed",
			logger.Field("error", err.Error()),
			logger.Field("messageLog", messageLog),
		)
		return nil
	}

	if err = l.svcCtx.LogModel.Insert(ctx, &log.SystemLog{
		Type:     log.TypeEmailMessage.Uint8(),
		Date:     time.Now().Format("2006-01-02"),
		ObjectID: 0,
		Content:  string(emailLog),
	}); err != nil {
		logger.WithContext(ctx).Error("[SendEmailLogic] Insert email log failed",
			logger.Field("error", err.Error()),
			logger.Field("emailLog", string(emailLog)),
		)
		return nil
	}
	return nil
}

func resolveVerifyScene(scene string, typeVal int) string {
	scene = strings.ToLower(strings.TrimSpace(scene))
	if scene != "" {
		return scene
	}
	return constant.ParseVerifyType(uint8(typeVal)).String()
}

func selectVerifyTemplate(sceneTemplates map[string]string, legacyTemplate string, scene string) string {
	if sceneTemplates != nil {
		if tpl := strings.TrimSpace(sceneTemplates[scene]); tpl != "" {
			return tpl
		}
		if tpl := strings.TrimSpace(sceneTemplates["default"]); tpl != "" {
			return tpl
		}
	}
	if strings.TrimSpace(legacyTemplate) != "" {
		return legacyTemplate
	}
	return email.DefaultEmailVerifyTemplate
}
