package infra

import (
	"fmt"
	"net"
	"strings"
	"testing"
)

// startMockSMTPForSend starts a mock SMTP server and returns host/port separately.
func startMockSMTPForSend(t *testing.T) (host string, port int, stop func()) {
	t.Helper()
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("mock smtp listen: %v", err)
	}
	go func() {
		for {
			conn, err := ln.Accept()
			if err != nil {
				return
			}
			go handleMockSMTP(conn)
		}
	}()
	h, ps, _ := net.SplitHostPort(ln.Addr().String())
	p := 0
	fmt.Sscanf(ps, "%d", &p)
	return h, p, func() { ln.Close() }
}


func TestSMTPSend(t *testing.T) {
	t.Run("envia mensaje texto plano via mock smtp", func(t *testing.T) {
		host, port, stop := startMockSMTPForSend(t)
		defer stop()

		cfg := SMTPConfig{Host: host, Port: port, TLSMode: ""}
		client, err := SMTPConnect(cfg)
		if err != nil {
			t.Fatalf("SMTPConnect: %v", err)
		}
		defer client.Quit()

		msg := EmailBuildText("alice@example.com", []string{"bob@example.com"}, "Test", "Hello Bob")
		if err := SMTPSend(client, msg); err != nil {
			t.Fatalf("SMTPSend: %v", err)
		}
	})

	t.Run("envia mensaje html via mock smtp", func(t *testing.T) {
		host, port, stop := startMockSMTPForSend(t)
		defer stop()

		cfg := SMTPConfig{Host: host, Port: port, TLSMode: ""}
		client, err := SMTPConnect(cfg)
		if err != nil {
			t.Fatalf("SMTPConnect: %v", err)
		}
		defer client.Quit()

		msg := EmailBuildHTML("alice@example.com", []string{"bob@example.com"}, "HTML Test", "<b>Hello</b>")
		if err := SMTPSend(client, msg); err != nil {
			t.Fatalf("SMTPSend: %v", err)
		}
	})

	t.Run("envia con adjunto via mock smtp", func(t *testing.T) {
		host, port, stop := startMockSMTPForSend(t)
		defer stop()

		cfg := SMTPConfig{Host: host, Port: port, TLSMode: ""}
		client, err := SMTPConnect(cfg)
		if err != nil {
			t.Fatalf("SMTPConnect: %v", err)
		}
		defer client.Quit()

		msg := EmailBuildText("alice@example.com", []string{"bob@example.com"}, "Att Test", "See attachment")
		att := EmailAttachment{Filename: "data.txt", ContentType: "text/plain", Data: []byte("file content")}
		msg = EmailWithAttachment(msg, att)

		if err := SMTPSend(client, msg); err != nil {
			t.Fatalf("SMTPSend with attachment: %v", err)
		}
	})
}

// TestExtractAddr tests the internal extractAddr helper.
func TestExtractAddr(t *testing.T) {
	cases := []struct {
		input string
		want  string
	}{
		{"Alice <alice@example.com>", "alice@example.com"},
		{"bob@example.com", "bob@example.com"},
		{"  carol@example.com  ", "carol@example.com"},
	}
	for _, c := range cases {
		got := extractAddr(c.input)
		if got != c.want {
			t.Errorf("extractAddr(%q) = %q, want %q", c.input, got, c.want)
		}
	}
}

// TestBuildMIME tests the MIME builder with different body combinations.
func TestBuildMIME(t *testing.T) {
	t.Run("solo texto plano", func(t *testing.T) {
		msg := EmailBuildText("a@a.com", []string{"b@b.com"}, "Subj", "Hello plain")
		body, err := buildMIME(msg)
		if err != nil {
			t.Fatalf("buildMIME: %v", err)
		}
		s := string(body)
		if !strings.Contains(s, "text/plain") {
			t.Errorf("expected text/plain in MIME, got:\n%s", s)
		}
		if !strings.Contains(s, "Hello plain") {
			t.Errorf("expected body text in MIME, got:\n%s", s)
		}
	})

	t.Run("solo html", func(t *testing.T) {
		msg := EmailBuildHTML("a@a.com", []string{"b@b.com"}, "Subj", "<b>Bold</b>")
		body, err := buildMIME(msg)
		if err != nil {
			t.Fatalf("buildMIME: %v", err)
		}
		s := string(body)
		if !strings.Contains(s, "text/html") {
			t.Errorf("expected text/html in MIME, got:\n%s", s)
		}
	})

	t.Run("multipart con adjunto", func(t *testing.T) {
		msg := EmailBuildText("a@a.com", []string{"b@b.com"}, "Subj", "body")
		att := EmailAttachment{Filename: "f.pdf", ContentType: "application/pdf", Data: []byte("pdf")}
		msg = EmailWithAttachment(msg, att)
		body, err := buildMIME(msg)
		if err != nil {
			t.Fatalf("buildMIME: %v", err)
		}
		s := string(body)
		if !strings.Contains(s, "multipart/mixed") {
			t.Errorf("expected multipart/mixed in MIME, got:\n%s", s)
		}
		if !strings.Contains(s, "f.pdf") {
			t.Errorf("expected attachment filename in MIME, got:\n%s", s)
		}
	})
}
