package owner

import (
	"context"
	"errors"
	"testing"

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

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

	require.True(t, NewAllSet().Has("wsp_1"))
	require.False(t, NewAllSet().Has(" "))

	static := NewStaticSet([]string{"wsp_1", " ", "wsp_2", "wsp_1"})
	require.True(t, static.Has("wsp_1"))
	require.True(t, static.Has(" wsp_2 "))
	require.False(t, static.Has("wsp_3"))
	require.False(t, static.Has(""))

	require.False(t, NewEmptySet().Has("wsp_1"))
	require.True(t, IsManaged(nil, "wsp_legacy"))
	require.NoError(t, Require(nil, "wsp_legacy"))
	require.ErrorIs(t, Require(static, "wsp_3"), ErrOwnerMismatch)
}

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

	loader := &fakeLoader{workspaceIDs: []string{"wsp_1", "wsp_2"}}
	set, err := LoadStaticSet(context.Background(), loader, " workspace-default ")
	require.NoError(t, err)
	require.Equal(t, "workspace-default", loader.workspaceGroupID)
	require.True(t, set.Has("wsp_1"))
	require.False(t, set.Has("wsp_3"))
}

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

	_, err := LoadStaticSet(context.Background(), nil, "workspace-default")
	require.EqualError(t, err, "workspace placement loader is not configured")

	_, err = LoadStaticSet(context.Background(), &fakeLoader{}, " ")
	require.EqualError(t, err, "workspace group id is required")

	boom := errors.New("boom")
	_, err = LoadStaticSet(context.Background(), &fakeLoader{err: boom}, "workspace-default")
	require.ErrorIs(t, err, boom)
	require.Contains(t, err.Error(), `load workspace placements for group "workspace-default"`)
}

type fakeLoader struct {
	workspaceIDs     []string
	workspaceGroupID string
	err              error
}

func (loader *fakeLoader) ListActiveWorkspaceIDsForGroup(_ context.Context, workspaceGroupID string) ([]string, error) {
	loader.workspaceGroupID = workspaceGroupID
	if loader.err != nil {
		return nil, loader.err
	}
	return loader.workspaceIDs, nil
}

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

	checker := &fakeGroupMembershipChecker{active: map[string]bool{"wsp_1": true}}
	set, err := NewGroupSet(checker, " workspace-default ")
	require.NoError(t, err)

	require.True(t, set.Has(" wsp_1 "))
	require.Equal(t, "workspace-default", checker.groupID)
	require.False(t, set.Has("wsp_2"))
}

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

	_, err := NewGroupSet(nil, "workspace-default")
	require.EqualError(t, err, "workspace placement checker is not configured")

	_, err = NewGroupSet(&fakeGroupMembershipChecker{}, " ")
	require.EqualError(t, err, "workspace group id is required")
}

type fakeGroupMembershipChecker struct {
	active  map[string]bool
	groupID string
	err     error
}

func (checker *fakeGroupMembershipChecker) IsWorkspaceRoutableToGroup(_ context.Context, workspaceID string, workspaceGroupID string) (bool, error) {
	checker.groupID = workspaceGroupID
	if checker.err != nil {
		return false, checker.err
	}
	return checker.active[workspaceID], nil
}
