package mail

import (
	"context"
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"net/smtp"
	"strings"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
)

type SmtpAyarlari struct {
	Host      string `bson:"smtpHost" json:"smtpHost"`
	Port      int    `bson:"smtpPort" json:"smtpPort"`
	Kullanici string `bson:"smtpKullanici" json:"smtpKullanici"`
	Sifre     string `bson:"smtpSifre" json:"smtpSifre"`
	Gonderen  string `bson:"smtpGonderen" json:"smtpGonderen"`
	TLS       bool   `bson:"smtpTLS" json:"smtpTLS"`
}

type MailService struct {
	koleksiyon func(string) *mongo.Collection
	ayarlar    *SmtpAyarlari
	sonYukleme time.Time
}

func YeniMailService(koleksiyonFn func(string) *mongo.Collection) *MailService {
	return &MailService{
		koleksiyon: koleksiyonFn,
	}
}

func (m *MailService) ayarlariYukle() *SmtpAyarlari {
	if m.ayarlar != nil && time.Since(m.sonYukleme) < 5*time.Minute {
		return m.ayarlar
	}
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	kol := m.koleksiyon("hareketler")
	if kol == nil {
		return nil
	}

	var sonuc SmtpAyarlari
	err := kol.FindOne(ctx, bson.M{"vt": "FikoYT.sistem.ayarlar.smtp"}).Decode(&sonuc)
	if err != nil {
		log.Printf("[Mail] SMTP ayarları bulunamadı: %v", err)
		return nil
	}

	m.ayarlar = &sonuc
	m.sonYukleme = time.Now()
	return m.ayarlar
}

func (m *MailService) Gonder(alici, konu, icerikHTML string) error {
	ayar := m.ayarlariYukle()
	if ayar == nil {
		return fmt.Errorf("SMTP ayarları bulunamadı")
	}
	return m.gonderInternal(ayar, []string{alici}, konu, icerikHTML)
}

func (m *MailService) TopluGonder(alicilar []string, konu, icerikHTML string) error {
	ayar := m.ayarlariYukle()
	if ayar == nil {
		return fmt.Errorf("SMTP ayarları bulunamadı")
	}
	return m.gonderInternal(ayar, alicilar, konu, icerikHTML)
}

func (m *MailService) gonderInternal(ayar *SmtpAyarlari, alicilar []string, konu, icerikHTML string) error {
	if len(alicilar) == 0 {
		return fmt.Errorf("alıcı adresi boş")
	}

	gonderen := ayar.Gonderen
	if gonderen == "" {
		gonderen = ayar.Kullanici
	}

	headers := make(map[string]string)
	headers["From"] = gonderen
	headers["To"] = strings.Join(alicilar, ", ")
	headers["Subject"] = konu
	headers["MIME-Version"] = "1.0"
	headers["Content-Type"] = "text/html; charset=\"utf-8\""
	headers["Date"] = time.Now().Format(time.RFC1123Z)

	var mesaj strings.Builder
	for k, v := range headers {
		mesaj.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
	}
	mesaj.WriteString("\r\n")
	mesaj.WriteString(icerikHTML)

	addr := fmt.Sprintf("%s:%d", ayar.Host, ayar.Port)
	auth := smtp.PlainAuth("", ayar.Kullanici, ayar.Sifre, ayar.Host)

	if ayar.TLS || ayar.Port == 465 {
		tlsConfig := &tls.Config{
			ServerName:         ayar.Host,
			InsecureSkipVerify: true,
		}
		conn, err := tls.Dial("tcp", addr, tlsConfig)
		if err != nil {
			return fmt.Errorf("TLS bağlantı hatası: %w", err)
		}
		defer conn.Close()

		client, err := smtp.NewClient(conn, ayar.Host)
		if err != nil {
			return fmt.Errorf("SMTP client hatası: %w", err)
		}
		defer client.Close()

		if err = client.Auth(auth); err != nil {
			return fmt.Errorf("SMTP auth hatası: %w", err)
		}
		if err = client.Mail(gonderen); err != nil {
			return fmt.Errorf("SMTP mail hatası: %w", err)
		}
		for _, alici := range alicilar {
			if err = client.Rcpt(alici); err != nil {
				return fmt.Errorf("SMTP rcpt hatası: %w", err)
			}
		}
		w, err := client.Data()
		if err != nil {
			return fmt.Errorf("SMTP data hatası: %w", err)
		}
		_, err = w.Write([]byte(mesaj.String()))
		if err != nil {
			return fmt.Errorf("SMTP write hatası: %w", err)
		}
		return w.Close()
	}

	// STARTTLS (port 587)
	conn, err := net.DialTimeout("tcp", addr, 10*time.Second)
	if err != nil {
		return fmt.Errorf("bağlantı hatası: %w", err)
	}
	defer conn.Close()

	client, err := smtp.NewClient(conn, ayar.Host)
	if err != nil {
		return fmt.Errorf("SMTP client hatası: %w", err)
	}
	defer client.Close()

	tlsConfig := &tls.Config{
		ServerName:         ayar.Host,
		InsecureSkipVerify: true,
	}
	if err = client.StartTLS(tlsConfig); err != nil {
		log.Printf("[Mail] STARTTLS başlatılamadı, devam ediliyor: %v", err)
	}
	if err = client.Auth(auth); err != nil {
		return fmt.Errorf("SMTP auth hatası: %w", err)
	}
	if err = client.Mail(gonderen); err != nil {
		return fmt.Errorf("SMTP mail hatası: %w", err)
	}
	for _, alici := range alicilar {
		if err = client.Rcpt(alici); err != nil {
			return fmt.Errorf("SMTP rcpt hatası: %w", err)
		}
	}
	w, err := client.Data()
	if err != nil {
		return fmt.Errorf("SMTP data hatası: %w", err)
	}
	_, err = w.Write([]byte(mesaj.String()))
	if err != nil {
		return fmt.Errorf("SMTP write hatası: %w", err)
	}
	return w.Close()
}
