package app

import (
	"fmt"
	"strings"
	"testing"

	"github.com/stretchr/testify/require"
)

func githubTargetEnvelope(items ...map[string]any) map[string]any {
	raw := make([]any, 0, len(items))
	for _, item := range items {
		raw = append(raw, item)
	}
	return map[string]any{
		githubConnectionTargetsSnapshotKey: map[string]any{
			"version":       githubConnectionTargetsVersion,
			"installations": raw,
		},
	}
}

func githubTargetItem(id, login, accountID string) map[string]any {
	return map[string]any{
		"installation_id": id,
		"account_login":   login,
		"account_id":      accountID,
	}
}

func TestNormalizeGitHubInstallationSelectionDoesNotizeClientWhitespace(t *testing.T) {
	t.Parallel()

	_, err := normalizeGitHubInstallationSelection(" 1 ", nil)
	require.ErrorIs(t, err, ErrBadRequest)
	_, err = normalizeGitHubInstallationSelection("", []string{" 1 "})
	require.ErrorIs(t, err, ErrBadRequest)
}

func TestParseGitHubConnectionTargetSnapshotsV1IsStrict(t *testing.T) {
	t.Parallel()

	actual, err := parseGitHubConnectionTargetSnapshots(githubTargetEnvelope(
		githubTargetItem("2", "acme", "20"),
		githubTargetItem("10", "beta", "30"),
	))
	require.NoError(t, err)
	require.Equal(t, []githubConnectionTargetSnapshot{
		{InstallationID: "2", AccountLogin: "acme", AccountID: "20"},
		{InstallationID: "10", AccountLogin: "beta", AccountID: "30"},
	}, actual)

	unknownEnvelope := githubTargetEnvelope(githubTargetItem("1", "acme", "1"))
	unknownEnvelope[githubConnectionTargetsSnapshotKey].(map[string]any)["unexpected"] = true
	unknownItem := githubTargetEnvelope(githubTargetItem("1", "acme", "1"))
	unknownItem[githubConnectionTargetsSnapshotKey].(map[string]any)["installations"].([]any)[0].(map[string]any)["unexpected"] = true
	nonArray := map[string]any{githubConnectionTargetsSnapshotKey: map[string]any{
		"version": githubConnectionTargetsVersion, "installations": "not-an-array",
	}}

	tooManyItems := make([]map[string]any, 0, githubConnectionTargetsMax+1)
	for index := 1; index <= githubConnectionTargetsMax+1; index++ {
		tooManyItems = append(tooManyItems, githubTargetItem(
			fmt.Sprintf("%d", index), fmt.Sprintf("org-%d", index), fmt.Sprintf("%d", index),
		))
	}
	for name, stored := range map[string]map[string]any{
		"unknown_envelope_key": unknownEnvelope,
		"unknown_item_key":     unknownItem,
		"non_array":            nonArray,
		"unordered": githubTargetEnvelope(
			githubTargetItem("10", "beta", "30"),
			githubTargetItem("2", "acme", "20"),
		),
		"duplicate": githubTargetEnvelope(
			githubTargetItem("2", "acme", "20"),
			githubTargetItem("2", "acme", "20"),
		),
		"too_many":           githubTargetEnvelope(tooManyItems...),
		"missing_account_id": githubTargetEnvelope(githubTargetItem("1", "acme", "")),
		"invalid_account_id": githubTargetEnvelope(githubTargetItem("1", "acme", "01")),
		"empty_login":        githubTargetEnvelope(githubTargetItem("1", "", "1")),
		"long_login": githubTargetEnvelope(githubTargetItem(
			"1", strings.Repeat("x", githubConnectionAccountLoginMax+1), "1",
		)),
	} {
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			_, err := parseGitHubConnectionTargetSnapshots(stored)
			require.ErrorIs(t, err, ErrConflict)
		})
	}
}
