package suite

import (
	"context"

	"code.justin.tv/eventbus/controlplane/e2e/internal/e2eutil"
	"code.justin.tv/eventbus/controlplane/e2e/internal/httpserver"
	"code.justin.tv/eventbus/controlplane/e2e/internal/report"
	"github.com/twitchtv/twirp"
)

var _ Runner = &EventTypeOwnershipTestSuite{}

// EventTypeOwnershipTestSuite performs operations that have expanded authZ allowances
// under the new event type ownership model. LDAP groups that aren't team-eventbus
// should be able to make modifications to event types they own. Services that own
// permissions should be able to relinquish those permissions.
type EventTypeOwnershipTestSuite struct {
	*DefaultTestSuite // Use the default suite as ground work
}

func NewEventTypeOwnershipTestSuite(suiteName string) (Runner, error) {
	defaultTestSuite, err := NewDefaultTestSuite(suiteName)
	if err != nil {
		return nil, err
	}

	return &EventTypeOwnershipTestSuite{
		DefaultTestSuite: defaultTestSuite,
	}, nil
}

func (t *EventTypeOwnershipTestSuite) Setup(ctx context.Context) report.Error {
	ctx = e2eutil.AppendTestPath(ctx, t.TestName())
	return t.DefaultTestSuite.Setup(ctx)
}

func (t *EventTypeOwnershipTestSuite) Test(ctx context.Context) {
	ctx = e2eutil.AppendTestPath(ctx, t.TestName())
	t.DefaultTestSuite.Test(ctx)

	// Event type owner granting publisher auth
	_, err := httpserver.AllowIAMRolePublish(
		e2eutil.JobID(ctx),
		"E2ECreate",
		"staging",
		"arn:aws:iam::567312298267:role/e2e-publisher-role",
		httpserver.WithLDAPUser("some-nobody"),
		httpserver.WithLDAPGroups([]string{"team-amazing"}),
	)
	if err != nil {
		t.Error(ctx, "failed to create publication", err)
		return
	}

	// Service owner revoking their own auth (they don't own the event type)
	_, err = httpserver.DeleteIAMRolePublication(
		e2eutil.JobID(ctx),
		"E2ECreate",
		"staging",
		"arn:aws:iam::567312298267:role/e2e-publisher-role",
		httpserver.WithLDAPUser("some-other-nobody"),
		httpserver.WithLDAPGroups([]string{"team-e2e-group1"}), // this group owns the service / iam role
	)
	if err != nil {
		t.Error(ctx, "failed to delete publication", err)
		return
	}

	// Non-Owner of event type trying to grant publisher auth
	_, err = httpserver.AllowIAMRolePublish(
		e2eutil.JobID(ctx),
		"E2ECreate",
		"staging",
		"arn:aws:iam::567312298267:role/blah",
		httpserver.WithLDAPUser("some-other-nobody"),
		httpserver.WithLDAPGroups([]string{"team-some-random-group"}), // completely incorrect group
	)
	if err == nil {
		t.Error(ctx, "expected to receive access denied creating publication", nil)
		return
	}
	twirpErr, ok := err.(twirp.Error)
	if !ok || twirpErr.Code() != twirp.NotFound {
		t.Error(ctx, "wrong error type received, expecting twirp.NotFound", err)
		return
	}

	// Event type owner can grant subscriber authorized field grant
	_, err = httpserver.CreateAuthorizedFieldSubscriberGrant(
		e2eutil.JobID(ctx),
		"E2EUpdate",
		"staging",
		"TopSecret",
		"AuthorizedEyesOnly",
		"arn:aws:iam::311539646041:role/e2e-subscriber-role",
		httpserver.WithLDAPUser("event-owner"),
		httpserver.WithLDAPGroups([]string{"team-coolpeeps"}),
	)
	if err != nil {
		t.Error(ctx, "unexpected error creating authorized field subscriber grant as event owner", err)
	}

	_, err = httpserver.CreateAuthorizedFieldSubscriberGrant(
		e2eutil.JobID(ctx),
		"E2EUpdate",
		"staging",
		"Foobar",
		"Garply",
		"arn:aws:iam::311539646041:role/e2e-subscriber-role",
		httpserver.WithLDAPUser("event-owner"),
		httpserver.WithLDAPGroups([]string{"team-coolpeeps"}),
	)
	if err != nil {
		t.Error(ctx, "unexpected error creating authorized field subscriber grant as event owner", err)
	}

	// Event type owner can revoke subscriber authorized field grant
	_, err = httpserver.DeleteAuthorizedFieldSubscriberGrant(
		e2eutil.JobID(ctx),
		"E2EUpdate",
		"staging",
		"TopSecret",
		"AuthorizedEyesOnly",
		"arn:aws:iam::311539646041:role/e2e-subscriber-role",
		httpserver.WithLDAPUser("event-owner"),
		httpserver.WithLDAPGroups([]string{"team-coolpeeps"}),
	)
	if err != nil {
		t.Error(ctx, "unexpected error creating authorized field subscriber grant as event owner", err)
	}

	// Subscriber owner can revoke authorized field grant
	_, err = httpserver.DeleteAuthorizedFieldSubscriberGrant(
		e2eutil.JobID(ctx),
		"E2EUpdate",
		"staging",
		"Foobar",
		"Garply",
		"arn:aws:iam::311539646041:role/e2e-subscriber-role",
		httpserver.WithLDAPUser("service-owner"),
		httpserver.WithLDAPGroups([]string{"team-delete-own-sub-grants"}),
	)
	if err != nil {
		t.Error(ctx, "unexpected error creating authorized field subscriber grant as event owner", err)
	}
}

func (t *EventTypeOwnershipTestSuite) Clean(ctx context.Context) []report.Error {
	ctx = e2eutil.AppendTestPath(ctx, t.TestName())
	return t.DefaultTestSuite.Clean(ctx)
}

func (t *EventTypeOwnershipTestSuite) TestName() string {
	return "EventTypeOwnershipTestSuite"
}
