// Recipe "workflow-state": read a document's workflow states and transitions, then move it to
// another state.
//
// Usage: go run ./recipes/workflow_state [workflow ID, default 107] [initial state ID, default
// 137] [target state ID, default 141] [--keep]
// With --keep the test document stays in the vault; otherwise it is deleted at the end.
package main

import (
	"context"
	"fmt"

	"github.com/M-Files/mfiles-grpc-api-samples/mfilesclient"
	"github.com/M-Files/mfiles-grpc-api-samples/recipes/internal/recipe"
	"github.com/M-Files/mfiles-grpc-api/go/mfiles"
)

func main() {
	recipe.Main(run)
}

func run(ctx context.Context) (err error) {
	workflowID := recipe.IntArg(0, 107)   // "Contract Approval Workflow" in the Sample Vault
	initialState := recipe.IntArg(1, 137) // "Draft"
	// "Rejected". "Waiting for Approval" (138) has a precondition: the Owner property is set.
	targetState := recipe.IntArg(2, 141)
	client, err := recipe.Connect(ctx)
	if err != nil {
		return err
	}
	defer client.Close()
	objects := mfiles.NewIRPCObjectOperationsClient(client.Conn)

	// A test document in the workflow: property 38 "Workflow" (value list 7) and
	// property 39 "Workflow State" (value list 8).
	created, err := recipe.CreateTestDocument(ctx, client, "workflow-state",
		mfilesclient.PropertyValue(38, mfilesclient.Lookup(7, workflowID)),
		mfilesclient.PropertyValue(39, mfilesclient.Lookup(8, initialState)))
	if err != nil {
		return err
	}
	objID := created.GetObjectInfo().GetObjId()
	fmt.Println("Created", recipe.Describe(created))
	if !recipe.Keep() {
		defer func() {
			if deleteErr := recipe.Delete(ctx, client, objID); err == nil {
				err = deleteErr
			}
		}()
	}

	// [START workflow-state]
	// The states and transitions of the workflow, with what this user may select for this
	// object in its current state.
	objVer := mfilesclient.ObjVer(objID.GetType(), objID.GetItemId().GetInternalId(),
		created.GetVersionInfo().GetVersion().GetInternalVersion())
	workflow, err := objects.GetWorkflowStatesAndTransitions(ctx,
		&mfiles.GetWorkflowStatesAndTransitionsRequest{
			WorkflowId:   workflowID,
			CurrentState: mfilesclient.Lookup(8, initialState),
			ObjVer:       objVer,
		})
	if err != nil {
		return err
	}
	for _, state := range workflow.GetStates() {
		fmt.Printf("  State %d %s: selectable %v\n", state.GetId(), state.GetName(),
			state.GetCanCurrentUserSelect())
	}
	for _, transition := range workflow.GetTransitions() {
		fmt.Printf("  Transition %d %s: %d -> %d, selectable %v\n", transition.GetId(),
			transition.GetName(), transition.GetFromStateId(), transition.GetToStateId(),
			transition.GetCanCurrentUserSelect())
	}

	// Change the state by setting property 39 "Workflow State" on the version just read.
	updated, err := objects.SetProperties(ctx, &mfiles.SetPropertiesRequest{
		ObjVer:                        objVer,
		AllowModifyingCheckedInObject: true,
		FailIfNewerVersionExists:      true,
		Properties: []*mfiles.PropertyValue{
			mfilesclient.PropertyValue(39, mfilesclient.Lookup(8, targetState)),
		},
	})
	if err != nil {
		return err
	}
	// [END workflow-state]

	latest := updated.GetObjectInfo().GetLatestVersion()
	for _, property := range latest.GetProperties() {
		if property.GetPropertyDef() == 39 {
			fmt.Printf("State is now %s, version %d\n", recipe.FormatValue(property.GetValue()),
				latest.GetObjectVersion().GetVersionInfo().GetVersion().GetInternalVersion())
		}
	}
	return nil
}
