package email

import (
	"fmt"
	"net/smtp"
	"os"
	"strings"
	"sync"
	"time"
)

var (
	global *Emailer
	mu     sync.RWMutex
)

type Emailer struct {
	mode     string
	filePath string
	host     string
	port     string
	username string
	password string
}

type Email struct {
	From    string
	To      []string
	Subject string
	Body    string
}

// Init initializes the global emailer with the provided settings
func Init(mode, filePath, host, port, username, password string) error {
	mu.Lock()
	defer mu.Unlock()

	emailer := &Emailer{
		mode:     mode,
		filePath: filePath,
		host:     host,
		port:     port,
		username: username,
		password: password,
	}

	if err := emailer.validate(); err != nil {
		return err
	}

	global = emailer
	return nil
}

// Get returns the global emailer instance (thread-safe)
func Get() *Emailer {
	mu.RLock()
	defer mu.RUnlock()
	if global == nil {
		panic("email not initialized - call Init first")
	}
	return global
}

// Send sends an email using the configured method (thread-safe)
func Send(email Email) error {
	emailer := Get()

	mu.RLock()
	defer mu.RUnlock()

	switch emailer.mode {
	case "file":
		return emailer.sendToFile(email)
	case "smtp":
		return emailer.sendViaSMTP(email)
	default:
		return fmt.Errorf("invalid email mode: %s", emailer.mode)
	}
}

func (e *Emailer) validate() error {
	if e.mode != "file" && e.mode != "smtp" {
		return fmt.Errorf("mode must be 'file' or 'smtp'")
	}
	if e.mode == "smtp" {
		if e.host == "" || e.username == "" || e.password == "" {
			return fmt.Errorf("smtp mode requires host, username, and password")
		}
	}
	if e.mode == "file" && e.filePath == "" {
		return fmt.Errorf("file mode requires filePath")
	}
	return nil
}

func (e *Emailer) sendToFile(email Email) error {
	content := fmt.Sprintf(`--- EMAIL ---
Time: %s
From: %s
To: %s
Subject: %s

%s

--- END EMAIL ---

`, time.Now().Format(time.RFC3339), email.From, strings.Join(email.To, ", "), email.Subject, email.Body)

	f, err := os.OpenFile(e.filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	_, err = f.WriteString(content)
	return err
}

func (e *Emailer) sendViaSMTP(email Email) error {
	auth := smtp.PlainAuth("", e.username, e.password, e.host)

	msg := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s",
		email.From,
		strings.Join(email.To, ", "),
		email.Subject,
		email.Body,
	)

	addr := e.host + ":" + e.port
	return smtp.SendMail(addr, auth, email.From, email.To, []byte(msg))
}
