package organization

import (
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

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

	runtime := startOrganizationServiceRuntime(t)
	owner := bootstrapOrganizationAdmin(t, runtime, "owner@example.com", "owner")
	target := createVerifiedOrganizationUser(t, runtime, "target@example.com", "target")
	other := createVerifiedOrganizationUser(t, runtime, "other@example.com", "other")

	organization, err := runtime.service.CreateOrganizationForUser(runtime.ctx, owner, "Acme Org", "acme-org")
	require.NoError(t, err)

	account, err := runtime.service.CreateOrganizationMemberForUser(runtime.ctx, owner.ID, organization.ID, "", target.Email, "member")
	require.NoError(t, err)
	require.NoError(t, setOrganizationDirectoryBackendForTests(runtime, organization.ID, organizationDirectoryBackendExternalShadow))

	account, err = runtime.service.MarkOrganizationMemberSynced(runtime.ctx, organization.ID, account.ID, MarkOrganizationSyncedParams{
		ExternalProvider: organizationProviderFeishu,
		ExternalID:       "ou_feishu_directory_user",
		SyncSource:       "feishu",
	})
	require.NoError(t, err)
	require.Equal(t, organizationProviderFeishu, account.ExternalProvider)
	require.Equal(t, "ou_feishu_directory_user", account.ExternalID)

	binding, err := runtime.service.UpsertOrganizationMemberAuthBinding(runtime.ctx, organization.ID, account.ID, UpsertOrganizationAuthBindingParams{
		AuthProvider:     organizationProviderFeishu,
		SubjectKey:       organizationAuthSubjectKeyOpenID,
		SubjectValue:     "ou_feishu_sso_subject",
		ProviderTenantID: "tenant-key-1",
	})
	require.NoError(t, err)
	require.Equal(t, organizationProviderFeishu, binding.AuthProvider)
	require.Equal(t, organizationAuthSubjectKeyOpenID, binding.SubjectKey)
	require.Equal(t, "ou_feishu_sso_subject", binding.SubjectValue)
	require.Equal(t, "tenant-key-1", binding.ProviderTenantID)

	var reloadedAccount OrganizationMemberView
	err = coredb.WithTx(runtime.ctx, runtime.service.db, func(tx coredb.Tx) error {
		var err error
		reloadedAccount, err = runtime.service.InTx(tx).loadOrganizationMemberView(runtime.ctx, tx, organization.ID, account.ID)
		return err
	})
	require.NoError(t, err)
	require.Equal(t, organizationProviderFeishu, reloadedAccount.ExternalProvider)
	require.Equal(t, "ou_feishu_directory_user", reloadedAccount.ExternalID)

	bindings, err := runtime.service.ListOrganizationMemberAuthBindings(runtime.ctx, organization.ID, account.ID)
	require.NoError(t, err)
	require.Len(t, bindings, 1)
	require.Equal(t, "ou_feishu_sso_subject", bindings[0].SubjectValue)

	foundBinding, found, err := runtime.service.FindOrganizationAuthBinding(runtime.ctx, organization.ID, organizationProviderFeishu, organizationAuthSubjectKeyOpenID, "ou_feishu_sso_subject")
	require.NoError(t, err)
	require.True(t, found)
	require.Equal(t, account.ID, foundBinding.OrganizationMemberID)

	updatedBinding, err := runtime.service.UpsertOrganizationMemberAuthBinding(runtime.ctx, organization.ID, account.ID, UpsertOrganizationAuthBindingParams{
		AuthProvider:     organizationProviderFeishu,
		SubjectKey:       organizationAuthSubjectKeyOpenID,
		SubjectValue:     "ou_feishu_sso_subject_v2",
		ProviderTenantID: "tenant-key-1",
	})
	require.NoError(t, err)
	require.Equal(t, binding.ID, updatedBinding.ID)
	require.Equal(t, "ou_feishu_sso_subject_v2", updatedBinding.SubjectValue)

	bindings, err = runtime.service.ListOrganizationMemberAuthBindings(runtime.ctx, organization.ID, account.ID)
	require.NoError(t, err)
	require.Len(t, bindings, 1)
	require.Equal(t, "ou_feishu_sso_subject_v2", bindings[0].SubjectValue)

	otherAccount, err := runtime.service.CreateOrganizationMemberForUser(runtime.ctx, owner.ID, organization.ID, "", other.Email, "member")
	require.NoError(t, err)

	_, err = runtime.service.UpsertOrganizationMemberAuthBinding(runtime.ctx, organization.ID, otherAccount.ID, UpsertOrganizationAuthBindingParams{
		AuthProvider: organizationProviderFeishu,
		SubjectKey:   organizationAuthSubjectKeyOpenID,
		SubjectValue: "ou_feishu_sso_subject_v2",
	})
	require.ErrorIs(t, err, storeerr.ErrConflict)
	require.Contains(t, err.Error(), "already bound")
}
