package mailruntime

import (
	"encoding/json"
	"strings"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/extension/providers/mail/mailstore"
	"github.com/tidbcloud/AgentTeam/internal/store/app"
)

func TestDecodeConnectionMaterialValidatesEnvelopeAndCapabilities(
	t *testing.T,
) {
	t.Parallel()

	key := []byte(strings.Repeat("k", 32))
	connection := statelessTestConnection(t, key)
	material, err := decodeConnectionMaterial(key, nil, connection)
	require.NoError(t, err)
	require.Equal(t, "CaseSensitive@example.com", material.SenderAddress)
	require.Equal(t, "imap.example.com", material.IMAP.Host)
	require.Equal(t, "smtp-secret", material.SMTP.Password)
	require.Equal(t, "Drafts", material.Capabilities.DraftMailbox)
	require.True(t, material.supports("create-draft"))
	require.True(t, material.supports("send-draft"))
	require.False(t, material.supports("prepare-send"))

	tampered := connection
	var config map[string]any
	require.NoError(t, json.Unmarshal(connection.Config, &config))
	config["senderAddress"] = "other@example.com"
	tampered.Config, _ = json.Marshal(config)
	_, err = decodeConnectionMaterial(key, nil, tampered)
	require.ErrorContains(t, err, "identity")

	_, err = decodeConnectionMaterial(
		[]byte(strings.Repeat("x", 32)),
		nil,
		connection,
	)
	require.ErrorContains(t, err, "decrypt")
}

func TestConnectionCapabilityGateRequiresExactDraftExtensions(
	t *testing.T,
) {
	t.Parallel()

	key := []byte(strings.Repeat("k", 32))
	connection := statelessTestConnection(t, key)
	var config storedConnectionConfig
	require.NoError(t, json.Unmarshal(connection.Config, &config))
	config.IMAP.Capabilities = []string{
		"IMAP4REV1",
		"SPECIAL-USE",
		"UIDPLUS",
	}
	digest, err := config.ComputeDigest()
	require.NoError(t, err)
	config.CapabilityDigest = digest
	connection.Config, err = json.Marshal(config)
	require.NoError(t, err)

	material, err := decodeConnectionMaterial(key, nil, connection)
	require.NoError(t, err)
	require.True(t, material.supports("create-draft"))
	require.False(t, material.supports("update-draft"))
	require.False(t, material.supports("prepare-send"))
}

func statelessTestConnection(
	t *testing.T,
	key []byte,
) mailstore.Connection {
	t.Helper()

	credentials, err := json.Marshal(storedCredentials{
		SchemaVersion: 1,
		IMAP: storedAuth{
			Username: "imap-user",
			Password: "imap-secret",
		},
		SMTP: storedAuth{
			Username: "smtp-user",
			Password: "smtp-secret",
		},
	})
	require.NoError(t, err)
	encrypted, err := app.EncryptStoredCredentialsJSON(
		key,
		credentials,
	)
	require.NoError(t, err)
	config := storedConnectionConfig{
		SchemaVersion:         1,
		SenderAddress:         "CaseSensitive@example.com",
		SenderAddressAccepted: true,
		IMAP: storedEndpoint{
			Host:    "imap.example.com",
			Port:    993,
			TLSMode: "implicit",
			Capabilities: []string{
				"CONDSTORE",
				"DRAFTS",
				"IMAP4REV1",
				"SPECIAL-USE",
				"UIDPLUS",
			},
			DraftMailbox: "Drafts",
		},
		SMTP: storedEndpoint{
			Host:         "smtp.example.com",
			Port:         587,
			TLSMode:      "starttls",
			Capabilities: []string{"8BITMIME"},
		},
	}
	config.CapabilityDigest, err = config.ComputeDigest()
	require.NoError(t, err)
	configJSON, err := json.Marshal(config)
	require.NoError(t, err)
	return mailstore.Connection{
		ID:                    "appconn_1",
		WorkspaceID:           "wsp_1",
		ServiceInstallationID: "appinst_1",
		ExternalSubjectRef: storedExternalSubjectRef(
			key,
			"CaseSensitive@example.com",
		),
		EncryptedCredentials: encrypted,
		Config:               configJSON,
		Generation:           "sha256:" + strings.Repeat("b", 64),
	}
}
