package main

import (
	"bytes"
	"fmt"
	"net/smtp"
	"text/template"

	"github.com/jordan-wright/email"
	"gorm.io/gorm"
)

type EmailTemplate struct {
	Subject string
	Body    string
}

var emailTemplates = map[string]EmailTemplate{
	"peer_created": {
		Subject: "New Peer Created: {{.Peer.IP}}",
		Body:    "Peer {{.Peer.IP}} was created on server {{.Server.Name}}.\nPublic Key: {{.Peer.PublicKey}}",
	},
	"peer_deleted": {
		Subject: "Peer Deleted: {{.Peer.IP}}",
		Body:    "Peer {{.Peer.IP}} was deleted from server {{.Server.Name}}.",
	},
	"policy_changed": {
		Subject: "Policy Updated for {{.Peer.IP}}",
		Body:    "Policy updated for peer {{.Peer.IP}} on server {{.Server.Name}}.\nChanges: {{range .Policy.Changes}}{{.}} {{end}}",
	},
}

func GetSMTPSettings() (settings SMTPSettings, err error) {
	err = db.First(&settings).Error
	if err == gorm.ErrRecordNotFound {
		return SMTPSettings{}, nil
	}
	return
}

func SaveSMTPSettings(settings SMTPSettings) error {
	var existing SMTPSettings
	if err := db.First(&existing).Error; err == gorm.ErrRecordNotFound {
		return db.Create(&settings).Error
	}
	return db.Model(&existing).Updates(settings).Error
}

func SendEmail(to, templateName string, data map[string]interface{}) error {
	settings, err := GetSMTPSettings()
	if err != nil {
		return err
	}
	if !settings.Enabled {
		return fmt.Errorf("SMTP is disabled")
	}
	
	template, ok := emailTemplates[templateName]
	if !ok {
		return fmt.Errorf("template %s not found", templateName)
	}
	
	subject, err := renderTemplate(template.Subject, data)
	if err != nil {
		return err
	}
	body, err := renderTemplate(template.Body, data)
	if err != nil {
		return err
	}
	
	e := email.NewEmail()
	e.From = fmt.Sprintf("%s <%s>", settings.FromName, settings.FromEmail)
	e.To = []string{to}
	e.Subject = subject
	e.Text = []byte(body)
	
	addr := fmt.Sprintf("%s:%d", settings.Server, settings.Port)
	if settings.UseAuth {
		return e.Send(addr, smtp.PlainAuth("", settings.Username, settings.Password, settings.Server))
	}
	return e.Send(addr, nil)
}

func TestSMTP(settings SMTPSettings) error {
	e := email.NewEmail()
	e.From = fmt.Sprintf("%s <%s>", settings.FromName, settings.FromEmail)
	e.To = []string{settings.FromEmail}
	e.Subject = "WGRplane SMTP Test"
	e.Text = []byte("This is a test email from WGRplane.")
	
	addr := fmt.Sprintf("%s:%d", settings.Server, settings.Port)
	if settings.UseAuth {
		return e.Send(addr, smtp.PlainAuth("", settings.Username, settings.Password, settings.Server))
	}
	return e.Send(addr, nil)
}

func renderTemplate(tmpl string, data map[string]interface{}) (string, error) {
	t, err := template.New("email").Parse(tmpl)
	if err != nil {
		return "", err
	}
	var buf bytes.Buffer
	if err := t.Execute(&buf, data); err != nil {
		return "", err
	}
	return buf.String(), nil
}

func NotifyPeerCreated(server *Server, peer *Peer) error {
	data := map[string]interface{}{
		"Server": server,
		"Peer":   peer,
	}
	return SendEmail(server.Endpoint, "peer_created", data)
}

func NotifyPeerDeleted(server *Server, peer *Peer) error {
	data := map[string]interface{}{
		"Server": server,
		"Peer":   peer,
	}
	return SendEmail(server.Endpoint, "peer_deleted", data)
}

func NotifyPolicyChanged(server *Server, peer *Peer, changes []string) error {
	data := map[string]interface{}{
		"Server": server,
		"Peer":   peer,
		"Policy": Policy{Action: "updated", Changes: changes},
	}
	return SendEmail(server.Endpoint, "policy_changed", data)
}
