// Code generated by dagger. DO NOT EDIT.

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log/slog"
	"os"
	"sort"

	telemetry "github.com/dagger/otel-go"
	"github.com/vektah/gqlparser/v2/gqlerror"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/sdk/resource"
	semconv "go.opentelemetry.io/otel/semconv/v1.40.0"
	"go.opentelemetry.io/otel/trace"

	"github.com/grafana/tanka/dagger/internal/dagger"

	"github.com/dagger/querybuilder"
)

var dag = dagger.Connect()

func Tracer() trace.Tracer {
	return otel.Tracer("dagger.io/sdk.go")
}

// used for local MarshalJSON implementations
var marshalCtx = context.Background()

// called by main()
func setMarshalContext(ctx context.Context) {
	marshalCtx = ctx
	dagger.SetMarshalContext(ctx)
}

type DaggerObject interface {
	querybuilder.GraphQLMarshaller
	ID(ctx context.Context) (dagger.ID, error)
}

type ExecError = dagger.ExecError

// ptr returns a pointer to the given value.
func ptr[T any](v T) *T {
	return &v
}

// convertSlice converts a slice of one type to a slice of another type using a
// converter function
func convertSlice[I any, O any](in []I, f func(I) O) []O {
	out := make([]O, len(in))
	for i, v := range in {
		out[i] = f(v)
	}
	return out
}

func (r Tanka) MarshalJSON() ([]byte, error) {
	var concrete struct{}
	return json.Marshal(&concrete)
}

func (r *Tanka) UnmarshalJSON(bs []byte) error {
	var concrete struct{}
	err := json.Unmarshal(bs, &concrete)
	if err != nil {
		return err
	}
	return nil
}

func main() {
	ctx := context.Background()

	// Direct slog to the new stderr. This is only for dev time debugging, and
	// runtime errors/warnings.
	slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
		Level: slog.LevelWarn,
	})))

	if err := dispatch(ctx); err != nil {
		os.Exit(2)
	}
}

func convertError(rerr error) *dagger.Error {
	if gqlErr := findSingleGQLError(rerr); gqlErr != nil {
		dagErr := dag.Error(gqlErr.Message)
		if gqlErr.Extensions != nil {
			keys := make([]string, 0, len(gqlErr.Extensions))
			for k := range gqlErr.Extensions {
				keys = append(keys, k)
			}
			sort.Strings(keys)
			for _, k := range keys {
				val, err := json.Marshal(gqlErr.Extensions[k])
				if err != nil {
					fmt.Println("failed to marshal error value:", err)
				}
				dagErr = dagErr.WithValue(k, dagger.JSON(val))
			}
		}
		return dagErr
	}
	return dag.Error(rerr.Error())
}

func findSingleGQLError(rerr error) *gqlerror.Error {
	switch x := rerr.(type) {
	case *gqlerror.Error:
		return x
	case interface{ Unwrap() []error }:
		return nil
	case interface{ Unwrap() error }:
		return findSingleGQLError(x.Unwrap())
	default:
		return nil
	}
}
func dispatch(ctx context.Context) (rerr error) {
	ctx = telemetry.InitEmbedded(ctx, resource.NewWithAttributes(
		semconv.SchemaURL,
		semconv.ServiceNameKey.String("dagger-go-sdk"),
		// TODO version?
	))
	defer telemetry.Close()

	// A lot of the "work" actually happens when we're marshalling the return
	// value, which entails getting object IDs, which happens in MarshalJSON,
	// which has no ctx argument, so we use this lovely global variable.
	setMarshalContext(ctx)

	fnCall := dag.CurrentFunctionCall()
	defer func() {
		if rerr != nil {
			if err := fnCall.ReturnError(ctx, convertError(rerr)); err != nil {
				fmt.Println("failed to return error:", err, "\noriginal error:", rerr)
			}
		}
	}()

	parentName, err := fnCall.ParentName(ctx)
	if err != nil {
		return fmt.Errorf("get parent name: %w", err)
	}
	fnName, err := fnCall.Name(ctx)
	if err != nil {
		return fmt.Errorf("get fn name: %w", err)
	}
	parentJson, err := fnCall.Parent(ctx)
	if err != nil {
		return fmt.Errorf("get fn parent: %w", err)
	}
	fnArgs, err := fnCall.InputArgs(ctx)
	if err != nil {
		return fmt.Errorf("get fn args: %w", err)
	}

	inputArgs := map[string][]byte{}
	for _, fnArg := range fnArgs {
		argName, err := fnArg.Name(ctx)
		if err != nil {
			return fmt.Errorf("get fn arg name: %w", err)
		}
		argValue, err := fnArg.Value(ctx)
		if err != nil {
			return fmt.Errorf("get fn arg value: %w", err)
		}
		inputArgs[argName] = []byte(argValue)
	}

	result, err := invoke(ctx, []byte(parentJson), parentName, fnName, inputArgs)
	if err != nil {
		return err
	}
	resultBytes, err := json.Marshal(result)
	if err != nil {
		return fmt.Errorf("marshal: %w", err)
	}

	if err := fnCall.ReturnValue(ctx, dagger.JSON(resultBytes)); err != nil {
		return fmt.Errorf("store return value: %w", err)
	}
	return nil
}
func invoke(ctx context.Context, parentJSON []byte, parentName string, fnName string, inputArgs map[string][]byte) (_ any, err error) {
	_ = inputArgs
	switch parentName {
	case "Tanka":
		switch fnName {
		case "AcceptanceTests":
			var parent Tanka
			err = json.Unmarshal(parentJSON, &parent)
			if err != nil {
				panic(fmt.Errorf("%s: %w", "failed to unmarshal parent object", err))
			}
			var rootDir *dagger.Directory
			if inputArgs["rootDir"] != nil {
				err = json.Unmarshal([]byte(inputArgs["rootDir"]), &rootDir)
				if err != nil {
					panic(fmt.Errorf("%s: %w", "failed to unmarshal input arg rootDir", err))
				}
			}
			var acceptanceTestsDir *dagger.Directory
			if inputArgs["acceptanceTestsDir"] != nil {
				err = json.Unmarshal([]byte(inputArgs["acceptanceTestsDir"]), &acceptanceTestsDir)
				if err != nil {
					panic(fmt.Errorf("%s: %w", "failed to unmarshal input arg acceptanceTestsDir", err))
				}
			}
			return (*Tanka).AcceptanceTests(&parent, ctx, rootDir, acceptanceTestsDir)
		case "Build":
			var parent Tanka
			err = json.Unmarshal(parentJSON, &parent)
			if err != nil {
				panic(fmt.Errorf("%s: %w", "failed to unmarshal parent object", err))
			}
			var rootDir *dagger.Directory
			if inputArgs["rootDir"] != nil {
				err = json.Unmarshal([]byte(inputArgs["rootDir"]), &rootDir)
				if err != nil {
					panic(fmt.Errorf("%s: %w", "failed to unmarshal input arg rootDir", err))
				}
			}
			return (*Tanka).Build(&parent, ctx, rootDir), nil
		case "GetGoVersion":
			var parent Tanka
			err = json.Unmarshal(parentJSON, &parent)
			if err != nil {
				panic(fmt.Errorf("%s: %w", "failed to unmarshal parent object", err))
			}
			var file *dagger.File
			if inputArgs["file"] != nil {
				err = json.Unmarshal([]byte(inputArgs["file"]), &file)
				if err != nil {
					panic(fmt.Errorf("%s: %w", "failed to unmarshal input arg file", err))
				}
			}
			return (*Tanka).GetGoVersion(&parent, ctx, file)
		default:
			return nil, fmt.Errorf("unknown function %s", fnName)
		}
	default:
		return nil, fmt.Errorf("unknown object %s", parentName)
	}
}
