package services

import (
	"bytes"
	"html/template"

	"gopkg.in/gomail.v2"

	"GoMembership/internal/config"
	"GoMembership/internal/constants"
	"GoMembership/internal/models"
	"GoMembership/pkg/logger"
)

type EmailService struct {
	dialer *gomail.Dialer
}

func NewEmailService(host string, port int, username string, password string) *EmailService {
	dialer := gomail.NewDialer(host, port, username, password)
	return &EmailService{dialer: dialer}
}

func (s *EmailService) SendEmail(to string, subject string, body string, replyTo string) error {
	msg := gomail.NewMessage()
	msg.SetHeader("From", s.dialer.Username)
	msg.SetHeader("To", to)
	msg.SetHeader("Subject", subject)
	if replyTo != "" {
		msg.SetHeader("REPLY_TO", replyTo)
	}
	msg.SetBody("text/html", body)

	if err := s.dialer.DialAndSend(msg); err != nil {
		logger.Error.Printf("Could not send email to %s: %v", to, err)
		return err
	}
	logger.Info.Printf("Email sent to %s", to)
	return nil
}

func ParseTemplate(filename string, data interface{}) (string, error) {
	// Read the email template file

	templateDir := config.Templates.MailPath
	tpl, err := template.ParseFiles(templateDir + "/" + filename)
	if err != nil {
		logger.Error.Printf("Failed to parse email template: %v", err)
		return "", err
	}

	// Buffer to hold the rendered template
	var tplBuffer bytes.Buffer
	if err := tpl.Execute(&tplBuffer, data); err != nil {
		logger.Error.Printf("Failed to execute email template: %v", err)
		return "", err
	}

	return tplBuffer.String(), nil
}

func (s *EmailService) SendVerificationEmail(user *models.User, token *string) error {
	// Prepare data to be injected into the template
	data := struct {
		FirstName string
		LastName  string
		Token     string
		BASEURL   string
	}{
		FirstName: user.FirstName,
		LastName:  user.LastName,
		Token:     *token,
		BASEURL:   config.Site.BaseURL,
	}

	subject := constants.MailVerificationSubject
	body, err := ParseTemplate("mail_verification.tmpl", data)
	if err != nil {
		logger.Error.Print("Couldn't send verification mail")
		return err
	}
	return s.SendEmail(user.Email, subject, body, "")

}

func (s *EmailService) SendWelcomeEmail(user *models.User) error {
	// Prepare data to be injected into the template
	data := struct {
		Company         string
		FirstName       string
		MembershipModel string
		BASEURL         string
		MembershipID    uint
		MembershipFee   float32
		Logo            string
		WebsiteTitle    string
		RentalFee       float32
	}{
		Company:         user.Company,
		FirstName:       user.FirstName,
		MembershipModel: user.Membership.SubscriptionModel.Name,
		MembershipID:    user.Membership.ID,
		MembershipFee:   float32(user.Membership.SubscriptionModel.MonthlyFee),
		RentalFee:       float32(user.Membership.SubscriptionModel.HourlyRate),
		BASEURL:         config.Site.BaseURL,
		WebsiteTitle:    config.Site.WebsiteTitle,
		Logo:            config.Templates.LogoURI,
	}

	subject := constants.MailWelcomeSubject
	body, err := ParseTemplate("mail_welcome.tmpl", data)
	if err != nil {
		logger.Error.Print("Couldn't send welcome mail")
		return err
	}
	return s.SendEmail(user.Email, subject, body, "")
}

func (s *EmailService) SendRegistrationNotification(user *models.User) error {
	// Prepare data to be injected into the template
	data := struct {
		FirstName       string
		DateOfBirth     string
		LastName        string
		MembershipModel string
		Address         string
		IBAN            string
		Email           string
		Phone           string
		City            string
		Company         string
		ZipCode         string
		BASEURL         string
		MembershipID    uint
		RentalFee       float32
		MembershipFee   float32
		Logo            string
		WebsiteTitle    string
	}{
		Company:         user.Company,
		FirstName:       user.FirstName,
		LastName:        user.LastName,
		MembershipModel: user.Membership.SubscriptionModel.Name,
		MembershipID:    user.Membership.ID,
		MembershipFee:   float32(user.Membership.SubscriptionModel.MonthlyFee),
		RentalFee:       float32(user.Membership.SubscriptionModel.HourlyRate),
		Address:         user.Address,
		ZipCode:         user.ZipCode,
		City:            user.City,
		DateOfBirth:     user.DateOfBirth.Format("20060102"),
		Email:           user.Email,
		Phone:           user.Phone,
		IBAN:            user.BankAccount.IBAN,
		BASEURL:         config.Site.BaseURL,
		Logo:            config.Templates.LogoURI,
		WebsiteTitle:    config.Site.WebsiteTitle,
	}

	subject := constants.MailRegistrationSubject
	body, err := ParseTemplate("mail_registration.tmpl", data)
	if err != nil {
		logger.Error.Print("Couldn't send admin notification mail")
		return err
	}
	return s.SendEmail(config.Recipients.UserRegistration, subject, body, "")
}

func (s *EmailService) RelayContactFormMessage(sender string, name string, message string) error {
	data := struct {
		Message      string
		Name         string
		BASEURL      string
		Logo         string
		WebsiteTitle string
	}{
		Message:      message,
		Name:         name,
		BASEURL:      config.Site.BaseURL,
		Logo:         config.Templates.LogoURI,
		WebsiteTitle: config.Site.WebsiteTitle,
	}
	subject := constants.MailContactSubject
	body, err := ParseTemplate("mail_contact_form.tmpl", data)
	if err != nil {
		logger.Error.Print("Couldn't send contact form message mail")
		return err
	}
	return s.SendEmail(config.Recipients.ContactForm, subject, body, sender)
}
