package relay

import (
	"path/filepath"
	"strings"
	"testing"

	"mailgoserver/internal/db"
	"mailgoserver/internal/mailstore"
)

func TestBuildBounceMessageContainsFailureDetails(t *testing.T) {
	content, messageID := buildBounceMessage("mail.example.com", "sender@example.com", "Hello", "orig-id@example.com", []Result{
		{Recipient: "nobody@remote.example", ErrorMessage: "MX lookup failed", ErrorCode: "MX"},
	})
	if messageID == "" {
		t.Fatal("expected a non-empty bounce Message-ID")
	}
	for _, want := range []string{
		"To: sender@example.com",
		"Subject: Undelivered Mail Returned to Sender",
		"From: Mail Delivery System <mailer-daemon@mail.example.com>",
		"Auto-Submitted: auto-replied",
		"nobody@remote.example",
		"MX lookup failed",
		"Subject: Hello",
		"Message-ID: <orig-id@example.com>",
	} {
		if !strings.Contains(content, want) {
			t.Errorf("expected bounce content to contain %q, got:\n%s", want, content)
		}
	}
}

func TestSendBounceNoOpWithoutSenderOrFailures(t *testing.T) {
	r := &Relay{Hostname: "mail.example.com"}
	if err := r.SendBounce("", "subj", "id", []Result{{Recipient: "x@example.com", ErrorMessage: "boom"}}); err != nil {
		t.Fatalf("expected nil error for empty sender, got %v", err)
	}
	if err := r.SendBounce("sender@example.com", "subj", "id", nil); err != nil {
		t.Fatalf("expected nil error for no failures, got %v", err)
	}
}

// newTestMailbox mirrors mailstore's own test helper of the same name — kept local
// since it's unexported there and this package needs its own small Store+mailbox
// fixture to test SendBounce's local-delivery shortcut.
func newTestMailbox(t *testing.T, email string) (*mailstore.Store, int64) {
	t.Helper()
	database, err := db.Open(filepath.Join(t.TempDir(), "test.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { database.Close() })

	domainID, err := database.CreateDomain("example.com")
	if err != nil {
		t.Fatal(err)
	}
	s := mailstore.New(database, mailstore.GenerateDEK(), t.TempDir())
	dek := mailstore.GenerateDEK()
	wrapped, nonce, err := s.WrapDEK(dek)
	if err != nil {
		t.Fatal(err)
	}
	hash, err := db.HashPassword("irrelevant-portal-password")
	if err != nil {
		t.Fatal(err)
	}
	mailboxID, err := database.CreateMailbox(email, hash, domainID, 1<<30, wrapped, nonce)
	if err != nil {
		t.Fatal(err)
	}
	return s, mailboxID
}

func TestSendBounceDeliversLocallyWhenRecipientIsLocalMailbox(t *testing.T) {
	store, mailboxID := newTestMailbox(t, "sender@example.com")
	r := &Relay{Hostname: "mail.example.com", Mailstore: store, Logger: nil}

	err := r.SendBounce("sender@example.com", "Hello", "orig-id@example.com", []Result{
		{Recipient: "nobody@remote.example", ErrorMessage: "MX lookup failed", ErrorCode: "MX"},
	})
	if err != nil {
		t.Fatalf("SendBounce: %v", err)
	}

	inbox, err := store.DB.ListMessagesInFolder(mailboxID, "INBOX")
	if err != nil {
		t.Fatal(err)
	}
	if len(inbox) != 1 {
		t.Fatalf("expected 1 bounce message in INBOX, got %d", len(inbox))
	}
	if inbox[0].CachedSubject != "Undelivered Mail Returned to Sender" {
		t.Errorf("bounce subject = %q", inbox[0].CachedSubject)
	}
}
