package mailer

import (
	"context"
	"errors"
	"testing"

	"github.com/aws/aws-sdk-go-v2/service/sesv2"
	sestypes "github.com/aws/aws-sdk-go-v2/service/sesv2/types"
	"github.com/stretchr/testify/require"
)

type stubSESClient struct {
	input *sesv2.SendEmailInput
	err   error
}

func (client *stubSESClient) SendEmail(_ context.Context, params *sesv2.SendEmailInput, _ ...func(*sesv2.Options)) (*sesv2.SendEmailOutput, error) {
	client.input = params
	if client.err != nil {
		return nil, client.err
	}
	return &sesv2.SendEmailOutput{}, nil
}

func TestSESMailerSendVerificationEmail(t *testing.T) {
	client := &stubSESClient{}
	mailer := newSESMailer("https://agentteam.example.com", "noreply@example.com", client, nil)

	err := mailer.SendVerificationEmail(context.Background(), "user@example.com", "tok_verification")
	require.NoError(t, err)
	require.Equal(t, "noreply@example.com", deref(client.input.FromEmailAddress))
	require.Equal(t, []string{"user@example.com"}, client.input.Destination.ToAddresses)
	require.Equal(t, "Verify your AgentTeam email", messageSubject(t, client.input.Content.Simple))
	require.Contains(t, messageText(t, client.input.Content.Simple), "tok_verification")
	require.Contains(t, messageText(t, client.input.Content.Simple), "https://agentteam.example.com/?verify=tok_verification")
}

func TestSESMailerSendWorkspaceInviteEmail(t *testing.T) {
	client := &stubSESClient{}
	mailer := newSESMailer("https://agentteam.example.com", "noreply@example.com", client, nil)

	err := mailer.SendWorkspaceInviteEmail(context.Background(), "invitee@example.com", "Ops HQ", "tok_invite")
	require.NoError(t, err)
	require.Equal(t, "Your AgentTeam workspace invite", messageSubject(t, client.input.Content.Simple))
	require.Contains(t, messageText(t, client.input.Content.Simple), "Ops HQ")
	require.Contains(t, messageText(t, client.input.Content.Simple), "tok_invite")
	require.Contains(t, messageText(t, client.input.Content.Simple), "https://agentteam.example.com/?invite=tok_invite")
}

func TestSESMailerSendOrganizationInviteEmail(t *testing.T) {
	client := &stubSESClient{}
	mailer := newSESMailer("https://agentteam.example.com", "noreply@example.com", client, nil)

	err := mailer.SendOrganizationInviteEmail(context.Background(), "invitee@example.com", "Acme Org", "tok_org_invite")
	require.NoError(t, err)
	require.Equal(t, "Your AgentTeam organization invite", messageSubject(t, client.input.Content.Simple))
	require.Contains(t, messageText(t, client.input.Content.Simple), "Acme Org")
	require.Contains(t, messageText(t, client.input.Content.Simple), "tok_org_invite")
	require.Contains(t, messageText(t, client.input.Content.Simple), "https://agentteam.example.com/?invite=tok_org_invite")
}

func TestPendingInviteLinkUsesStableInviteIDPath(t *testing.T) {
	require.Equal(t, "https://agentteam.example.com/app/invite/inv_1", PendingInviteLink("https://agentteam.example.com/app", "inv_1"))
}

func TestSESMailerPropagatesSendError(t *testing.T) {
	client := &stubSESClient{err: errors.New("boom")}
	mailer := newSESMailer("https://agentteam.example.com", "noreply@example.com", client, nil)

	err := mailer.SendVerificationEmail(context.Background(), "user@example.com", "tok_verification")
	require.EqualError(t, err, "send email via SES (productionAccessEnabled=unknown): boom")
}

func TestSESMailerPropagatesSendErrorWhenProductionAccessEnabledTrue(t *testing.T) {
	enabled := true
	client := &stubSESClient{err: errors.New("boom")}
	mailer := newSESMailer("https://agentteam.example.com", "noreply@example.com", client, &enabled)

	err := mailer.SendVerificationEmail(context.Background(), "user@example.com", "tok_verification")
	require.EqualError(t, err, "send email via SES (productionAccessEnabled=true): boom")
}

func TestSESMailerPropagatesSendErrorWhenProductionAccessEnabledFalse(t *testing.T) {
	enabled := false
	client := &stubSESClient{err: errors.New("boom")}
	mailer := newSESMailer("https://agentteam.example.com", "noreply@example.com", client, &enabled)

	err := mailer.SendVerificationEmail(context.Background(), "user@example.com", "tok_verification")
	require.EqualError(t, err, "send email via SES (productionAccessEnabled=false): boom")
}

func messageSubject(t *testing.T, message *sestypes.Message) string {
	t.Helper()
	require.NotNil(t, message)
	require.NotNil(t, message.Subject)
	return deref(message.Subject.Data)
}

func messageText(t *testing.T, message *sestypes.Message) string {
	t.Helper()
	require.NotNil(t, message)
	require.NotNil(t, message.Body)
	require.NotNil(t, message.Body.Text)
	return deref(message.Body.Text.Data)
}

func deref(value *string) string {
	if value == nil {
		return ""
	}
	return *value
}
