package dbauthz

import (
	"context"

	"github.com/google/uuid"
	"golang.org/x/xerrors"

	"github.com/coder/coder/v2/coderd/database"
)

// AccessControlStore fetches access control-related configuration
// that is used when determining whether an actor is authorized
// to interact with an RBAC object.
type AccessControlStore interface {
	GetTemplateAccessControl(t database.Template) TemplateAccessControl
	SetTemplateAccessControl(ctx context.Context, store database.Store, id uuid.UUID, opts TemplateAccessControl) error
}

type TemplateAccessControl struct {
	RequireActiveVersion bool
	Deprecated           string
}

func (t TemplateAccessControl) IsDeprecated() bool {
	return t.Deprecated != ""
}

// AGPLTemplateAccessControlStore always returns the defaults for access control
// settings.
type AGPLTemplateAccessControlStore struct{}

var _ AccessControlStore = AGPLTemplateAccessControlStore{}

func (AGPLTemplateAccessControlStore) GetTemplateAccessControl(t database.Template) TemplateAccessControl {
	return TemplateAccessControl{
		RequireActiveVersion: false,
		// AGPL cannot set deprecated templates, but it should return
		// existing deprecated templates. This is erroring on the safe side
		// if a license expires, we should not allow deprecated templates
		// to be used for new workspaces.
		Deprecated: t.Deprecated,
	}
}

func (AGPLTemplateAccessControlStore) SetTemplateAccessControl(ctx context.Context, store database.Store, id uuid.UUID, opts TemplateAccessControl) error {
	// AGPL is allowed to unset deprecated templates.
	if opts.Deprecated == "" {
		// This does require fetching again to ensure other fields are not
		// changed.
		tpl, err := store.GetTemplateByID(ctx, id)
		if err != nil {
			return xerrors.Errorf("get template: %w", err)
		}

		if tpl.Deprecated != "" {
			err := store.UpdateTemplateAccessControlByID(ctx, database.UpdateTemplateAccessControlByIDParams{
				ID:                   id,
				RequireActiveVersion: tpl.RequireActiveVersion,
				Deprecated:           opts.Deprecated,
			})
			if err != nil {
				return xerrors.Errorf("update template access control: %w", err)
			}
		}
	}

	return nil
}
