package mailimp

import (
	"fmt"
	"testing"
)

// Mock implementations for testing

type mockLocalizer struct {
	localizeTemplateFunc func(id string, templateData, ctr any, lang string) (string, error)
	localizeStringFunc   func(id, lang string) (string, error)
	serviceName          string
	supportMail          string
}

func (m *mockLocalizer) LocalizeTemplate(id string, templateData, ctr any, lang string) (string, error) {
	if m.localizeTemplateFunc != nil {
		return m.localizeTemplateFunc(id, templateData, ctr, lang)
	}
	// Return a simple HTML template for testing
	return fmt.Sprintf("<html><body>Template: %s</body></html>", id), nil
}

func (m *mockLocalizer) LocalizeString(id, lang string) (string, error) {
	if m.localizeStringFunc != nil {
		return m.localizeStringFunc(id, lang)
	}
	return fmt.Sprintf("string:%s", id), nil
}

func (m *mockLocalizer) ServiceName() string {
	if m.serviceName != "" {
		return m.serviceName
	}
	return "TestService"
}

func (m *mockLocalizer) SupportMail() string {
	if m.supportMail != "" {
		return m.supportMail
	}
	return "support@test.com"
}

type mockDomainProvider struct {
	getFullLinkFunc func(linkElem ...string) (string, error)
	getAPILinkFunc  func(linkElem ...string) (string, error)
}

func (m *mockDomainProvider) GetFullLink(linkElem ...string) (string, error) {
	if m.getFullLinkFunc != nil {
		return m.getFullLinkFunc(linkElem...)
	}
	return "https://example.com/link", nil
}

func (m *mockDomainProvider) GetAPILink(linkElem ...string) (string, error) {
	if m.getAPILinkFunc != nil {
		return m.getAPILinkFunc(linkElem...)
	}
	return "https://api.example.com/link", nil
}

// Tests

func TestMessageImp_TemplateID_ReturnsCorrectValue(t *testing.T) {
	msg := createMessageImp()
	msg.templateID = "welcome"

	if msg.TemplateID() != "welcome" {
		t.Errorf("Expected templateID 'welcome', got '%s'", msg.TemplateID())
	}
}

func TestMessageImp_Locale_ReturnsCorrectValue(t *testing.T) {
	msg := createMessageImp()
	msg.locale = "en-US"

	if msg.Locale() != "en-US" {
		t.Errorf("Expected locale 'en-US', got '%s'", msg.Locale())
	}
}

func TestMessageImp_AccountID_ReturnsCorrectValue(t *testing.T) {
	msg := createMessageImp()
	msg.accountUID = "507f1f77bcf86cd799439011"

	if msg.AccountID() != "507f1f77bcf86cd799439011" {
		t.Errorf("Expected accountUID '507f1f77bcf86cd799439011', got '%s'", msg.AccountID())
	}
}

func TestMessageImp_Recipients_ReturnsCorrectList(t *testing.T) {
	msg := createMessageImp()
	msg.recipients = []string{"user1@example.com", "user2@example.com"}

	recipients := msg.Recipients()
	if len(recipients) != 2 {
		t.Fatalf("Expected 2 recipients, got %d", len(recipients))
	}
	if recipients[0] != "user1@example.com" {
		t.Errorf("Expected first recipient 'user1@example.com', got '%s'", recipients[0])
	}
	if recipients[1] != "user2@example.com" {
		t.Errorf("Expected second recipient 'user2@example.com', got '%s'", recipients[1])
	}
}

func TestMessageImp_Parameters_ReturnsCorrectMap(t *testing.T) {
	msg := createMessageImp()
	msg.parameters["key1"] = "value1"
	msg.parameters["key2"] = "value2"

	params := msg.Parameters()
	if len(params) != 2 {
		t.Fatalf("Expected 2 parameters, got %d", len(params))
	}
	if params["key1"] != "value1" {
		t.Errorf("Expected key1='value1', got '%v'", params["key1"])
	}
	if params["key2"] != "value2" {
		t.Errorf("Expected key2='value2', got '%v'", params["key2"])
	}
}

func TestMessageImp_Body_WithButton_CallsOneButtonTemplate(t *testing.T) {
	msg := createMessageImp()
	msg.templateID = "welcome"
	msg.locale = "en-US"
	msg.buttonLink = "https://example.com/verify"

	mockLoc := &mockLocalizer{
		localizeStringFunc: func(id, lang string) (string, error) {
			// Mock all localization calls that might occur
			switch id {
			case "btn.welcome":
				return "Verify Account", nil
			case "service.owner", "service.name":
				return "Test Service", nil
			default:
				return fmt.Sprintf("localized:%s", id), nil
			}
		},
	}
	mockDP := &mockDomainProvider{}

	body, err := msg.Body(mockLoc, mockDP)

	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if body == "" {
		t.Error("Expected non-empty body")
	}
	// Body should be HTML from one-button template
	// We can't test exact content without knowing template implementation,
	// but we can verify it succeeded
}

func TestMessageImp_Body_WithoutButton_CallsEmailNotification(t *testing.T) {
	msg := createMessageImp()
	msg.templateID = "notification"
	msg.locale = "en-US"
	msg.buttonLink = "" // No button

	mockLoc := &mockLocalizer{}
	mockDP := &mockDomainProvider{}

	body, err := msg.Body(mockLoc, mockDP)

	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if body == "" {
		t.Error("Expected non-empty body")
	}
}

func TestMessageImp_Body_LocalizationError_ReturnsError(t *testing.T) {
	msg := createMessageImp()
	msg.templateID = "welcome"
	msg.locale = "invalid-locale"
	msg.buttonLink = "https://example.com/verify"

	mockLoc := &mockLocalizer{
		localizeStringFunc: func(id, lang string) (string, error) {
			return "", fmt.Errorf("localization failed for lang: %s", lang)
		},
	}
	mockDP := &mockDomainProvider{}

	_, err := msg.Body(mockLoc, mockDP)

	if err == nil {
		t.Error("Expected error from localization failure")
	}
}

func TestCreateMessageImp_InitializesEmptyCollections(t *testing.T) {
	msg := createMessageImp()

	if msg.parameters == nil {
		t.Error("Expected parameters map to be initialized")
	}
	if msg.recipients == nil {
		t.Error("Expected recipients slice to be initialized")
	}
	if len(msg.parameters) != 0 {
		t.Error("Expected parameters map to be empty")
	}
	if len(msg.recipients) != 0 {
		t.Error("Expected recipients slice to be empty")
	}
}

func TestMessageImp_MultipleParameterTypes_StoresCorrectly(t *testing.T) {
	msg := createMessageImp()
	msg.parameters["string"] = "value"
	msg.parameters["number"] = 42
	msg.parameters["bool"] = true

	params := msg.Parameters()

	if params["string"] != "value" {
		t.Error("String parameter not stored correctly")
	}
	if params["number"] != 42 {
		t.Error("Number parameter not stored correctly")
	}
	if params["bool"] != true {
		t.Error("Boolean parameter not stored correctly")
	}
}

func TestMessageImp_EmptyTemplateID_AllowedByGetter(t *testing.T) {
	msg := createMessageImp()
	msg.templateID = ""

	// Should not panic or error
	result := msg.TemplateID()
	if result != "" {
		t.Errorf("Expected empty string, got '%s'", result)
	}
}

func TestMessageImp_EmptyLocale_AllowedByGetter(t *testing.T) {
	msg := createMessageImp()
	msg.locale = ""

	// Should not panic or error
	result := msg.Locale()
	if result != "" {
		t.Errorf("Expected empty string, got '%s'", result)
	}
}
