// Recipe "errors": provoke "not found" and "access denied" and show the decoded M-Files errors.
//
// Usage: go run ./recipes/errors
package main

import (
	"context"
	"fmt"
	"slices"
	"strings"

	"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) error {
	client, err := recipe.Connect(ctx)
	if err != nil {
		return err
	}
	defer client.Close()

	// [START errors]
	// Not found: a document ID that does not exist.
	objects := mfiles.NewIRPCObjectOperationsClient(client.Conn)
	_, err = objects.GetObjectInfoAndProperties(ctx, &mfiles.GetObjectInfoAndPropertiesRequest{
		ObjId:         mfilesclient.ObjID(0, 999_999_999),
		LatestVersion: true,
	})
	if mfilesErr, ok := mfilesclient.AsError(err); ok && mfilesErr.Has(mfilesclient.CodeNotFound) {
		printError("Not found", mfilesErr)
	} else {
		return fmt.Errorf("expected a not-found error, got %v", err)
	}

	// Access denied: an administrative call by a user who is not a vault administrator.
	admin := mfiles.NewIRPCPropertyDefsAdminClient(client.Conn)
	_, err = admin.GetPropertyDefsAdmin(ctx, &mfiles.GetPropertyDefsAdminRequest{})
	switch mfilesErr, ok := mfilesclient.AsError(err); {
	case err == nil:
		fmt.Println("Access denied: not provoked, the user is a vault administrator")
	case ok && mfilesErr.Has(mfilesclient.CodeAccessDenied):
		printError("Access denied", mfilesErr)
	default:
		return err
	}
	// [END errors]
	return nil
}

// [START print-error]

func printError(label string, err *mfilesclient.Error) {
	fmt.Printf("%s: gRPC status %s, M-Files error 0x%08X (%d)\n", label, err.Status.Code(),
		err.HResult, err.SignedHResult())
	fmt.Printf("  Message: %s\n", strings.Join(strings.Fields(err.Message), " "))
	var codes []string
	for _, c := range err.Codes {
		code := fmt.Sprintf("0x%08X", c)
		if !slices.Contains(codes, code) {
			codes = append(codes, code)
		}
	}
	fmt.Printf("  Error stack, original error first: %s\n", strings.Join(codes, ", "))
}

// [END print-error]
