package graph

// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
// Code generated by github.com/99designs/gqlgen version v0.17.75

import (
	"context"
	"fmt"
	"os"
	"slices"
	"time"

	"github.com/99designs/gqlgen/graphql/handler/transport"
	semver "github.com/Masterminds/semver/v3"
	"github.com/kubetail-org/kubetail/modules/dashboard/graph/model"
	sharedcfg "github.com/kubetail-org/kubetail/modules/shared/config"
	gqlerrors "github.com/kubetail-org/kubetail/modules/shared/graphql/errors"
	"github.com/kubetail-org/kubetail/modules/shared/helm"
	"github.com/kubetail-org/kubetail/modules/shared/k8shelpers"
	"github.com/kubetail-org/kubetail/modules/shared/logs"
	zlog "github.com/rs/zerolog/log"
	"helm.sh/helm/v3/pkg/release"
	appsv1 "k8s.io/api/apps/v1"
	batchv1 "k8s.io/api/batch/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/tools/clientcmd/api"
	"k8s.io/utils/ptr"
)

// Object is the resolver for the object field.
func (r *appsV1DaemonSetsWatchEventResolver) Object(ctx context.Context, obj *watch.Event) (*appsv1.DaemonSet, error) {
	return typeassertRuntimeObject[*appsv1.DaemonSet](obj.Object)
}

// Object is the resolver for the object field.
func (r *appsV1DeploymentsWatchEventResolver) Object(ctx context.Context, obj *watch.Event) (*appsv1.Deployment, error) {
	return typeassertRuntimeObject[*appsv1.Deployment](obj.Object)
}

// Object is the resolver for the object field.
func (r *appsV1ReplicaSetsWatchEventResolver) Object(ctx context.Context, obj *watch.Event) (*appsv1.ReplicaSet, error) {
	return typeassertRuntimeObject[*appsv1.ReplicaSet](obj.Object)
}

// Object is the resolver for the object field.
func (r *appsV1StatefulSetsWatchEventResolver) Object(ctx context.Context, obj *watch.Event) (*appsv1.StatefulSet, error) {
	return typeassertRuntimeObject[*appsv1.StatefulSet](obj.Object)
}

// Object is the resolver for the object field.
func (r *batchV1CronJobsWatchEventResolver) Object(ctx context.Context, obj *watch.Event) (*batchv1.CronJob, error) {
	return typeassertRuntimeObject[*batchv1.CronJob](obj.Object)
}

// Object is the resolver for the object field.
func (r *batchV1JobsWatchEventResolver) Object(ctx context.Context, obj *watch.Event) (*batchv1.Job, error) {
	return typeassertRuntimeObject[*batchv1.Job](obj.Object)
}

// Object is the resolver for the object field.
func (r *coreV1NamespacesWatchEventResolver) Object(ctx context.Context, obj *watch.Event) (*corev1.Namespace, error) {
	return typeassertRuntimeObject[*corev1.Namespace](obj.Object)
}

// Object is the resolver for the object field.
func (r *coreV1NodesWatchEventResolver) Object(ctx context.Context, obj *watch.Event) (*corev1.Node, error) {
	return typeassertRuntimeObject[*corev1.Node](obj.Object)
}

// Object is the resolver for the object field.
func (r *coreV1PodsWatchEventResolver) Object(ctx context.Context, obj *watch.Event) (*corev1.Pod, error) {
	return typeassertRuntimeObject[*corev1.Pod](obj.Object)
}

// Object is the resolver for the object field.
func (r *coreV1ServicesWatchEventResolver) Object(ctx context.Context, obj *watch.Event) (*corev1.Service, error) {
	return typeassertRuntimeObject[*corev1.Service](obj.Object)
}

// AuthInfos is the resolver for the authInfos field.
func (r *kubeConfigResolver) AuthInfos(ctx context.Context, obj *model.KubeConfig) ([]*model.KubeConfigAuthInfo, error) {
	outList := make([]*model.KubeConfigAuthInfo, len(obj.Config.AuthInfos))
	i := 0
	for name, val := range obj.Config.AuthInfos {
		outList[i] = &model.KubeConfigAuthInfo{
			AuthInfo: val,
			Name:     name,
		}
		i += 1
	}
	return outList, nil
}

// Clusters is the resolver for the clusters field.
func (r *kubeConfigResolver) Clusters(ctx context.Context, obj *model.KubeConfig) ([]*model.KubeConfigCluster, error) {
	outList := make([]*model.KubeConfigCluster, len(obj.Config.Clusters))
	i := 0
	for name, val := range obj.Config.Clusters {
		outList[i] = &model.KubeConfigCluster{
			Cluster: val,
			Name:    name,
		}
		i += 1
	}
	return outList, nil
}

// Contexts is the resolver for the contexts field.
func (r *kubeConfigResolver) Contexts(ctx context.Context, obj *model.KubeConfig) ([]*model.KubeConfigContext, error) {
	outList := make([]*model.KubeConfigContext, len(obj.Config.Contexts))
	i := 0
	for name, val := range obj.Config.Contexts {
		outList[i] = &model.KubeConfigContext{
			Context: val,
			Name:    name,
		}
		i += 1
	}
	return outList, nil
}

// HelmInstallLatest is the resolver for the helmInstallLatest field.
func (r *mutationResolver) HelmInstallLatest(ctx context.Context, kubeContext *string) (*release.Release, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Reject requests not in desktop environment
	if r.environment != sharedcfg.EnvironmentDesktop {
		return nil, gqlerrors.ErrForbidden
	}

	// Init client
	client := helm.NewClient(helm.WithKubeconfigPath(r.cfg.KubeconfigPath), helm.WithKubeContext(kubeContextVal))

	// Install
	release, err := client.InstallLatest(helm.DefaultNamespace, helm.DefaultReleaseName)
	if err != nil {
		return nil, err
	}

	return release, nil
}

// AppsV1DaemonSetsGet is the resolver for the appsV1DaemonSetsGet field.
func (r *queryResolver) AppsV1DaemonSetsGet(ctx context.Context, kubeContext *string, namespace *string, name string, options *metav1.GetOptions) (*appsv1.DaemonSet, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Deref namespace
	ns, err := k8shelpers.DerefNamespace(r.allowedNamespaces, namespace, r.cm.GetDefaultNamespace(kubeContextVal))
	if err != nil {
		return nil, err
	}

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.GetOptions{})

	// Execute
	return clientset.AppsV1().DaemonSets(ns).Get(ctx, name, opts)
}

// AppsV1DaemonSetsList is the resolver for the appsV1DaemonSetsList field.
func (r *queryResolver) AppsV1DaemonSetsList(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (*appsv1.DaemonSetList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outList := &appsv1.DaemonSetList{}
	if err := r.listResource(ctx, kubeContextVal, namespace, options, outList); err != nil {
		return nil, err
	}

	return outList, nil
}

// AppsV1DeploymentsGet is the resolver for the appsV1DeploymentsGet field.
func (r *queryResolver) AppsV1DeploymentsGet(ctx context.Context, kubeContext *string, namespace *string, name string, options *metav1.GetOptions) (*appsv1.Deployment, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Deref namespace
	ns, err := k8shelpers.DerefNamespace(r.allowedNamespaces, namespace, r.cm.GetDefaultNamespace(kubeContextVal))
	if err != nil {
		return nil, err
	}

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.GetOptions{})

	// Execute
	return clientset.AppsV1().Deployments(ns).Get(ctx, name, opts)
}

// AppsV1DeploymentsList is the resolver for the appsV1DeploymentsList field.
func (r *queryResolver) AppsV1DeploymentsList(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (*appsv1.DeploymentList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outList := &appsv1.DeploymentList{}
	if err := r.listResource(ctx, kubeContextVal, namespace, options, outList); err != nil {
		return nil, err
	}

	return outList, nil
}

// AppsV1ReplicaSetsGet is the resolver for the appsV1ReplicaSetsGet field.
func (r *queryResolver) AppsV1ReplicaSetsGet(ctx context.Context, kubeContext *string, namespace *string, name string, options *metav1.GetOptions) (*appsv1.ReplicaSet, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Deref namespace
	ns, err := k8shelpers.DerefNamespace(r.allowedNamespaces, namespace, r.cm.GetDefaultNamespace(kubeContextVal))
	if err != nil {
		return nil, err
	}

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.GetOptions{})

	// Execute
	return clientset.AppsV1().ReplicaSets(ns).Get(ctx, name, opts)
}

// AppsV1ReplicaSetsList is the resolver for the appsV1ReplicaSetsList field.
func (r *queryResolver) AppsV1ReplicaSetsList(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (*appsv1.ReplicaSetList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outList := &appsv1.ReplicaSetList{}
	if err := r.listResource(ctx, kubeContextVal, namespace, options, outList); err != nil {
		return nil, err
	}

	return outList, nil
}

// AppsV1StatefulSetsGet is the resolver for the appsV1StatefulSetsGet field.
func (r *queryResolver) AppsV1StatefulSetsGet(ctx context.Context, kubeContext *string, namespace *string, name string, options *metav1.GetOptions) (*appsv1.StatefulSet, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Deref namespace
	ns, err := k8shelpers.DerefNamespace(r.allowedNamespaces, namespace, r.cm.GetDefaultNamespace(kubeContextVal))
	if err != nil {
		return nil, err
	}

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.GetOptions{})

	// Execute
	return clientset.AppsV1().StatefulSets(ns).Get(ctx, name, opts)
}

// AppsV1StatefulSetsList is the resolver for the appsV1StatefulSetsList field.
func (r *queryResolver) AppsV1StatefulSetsList(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (*appsv1.StatefulSetList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outList := &appsv1.StatefulSetList{}
	if err := r.listResource(ctx, kubeContextVal, namespace, options, outList); err != nil {
		return nil, err
	}

	return outList, nil
}

// BatchV1CronJobsGet is the resolver for the batchV1CronJobsGet field.
func (r *queryResolver) BatchV1CronJobsGet(ctx context.Context, kubeContext *string, namespace *string, name string, options *metav1.GetOptions) (*batchv1.CronJob, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Deref namespace
	ns, err := k8shelpers.DerefNamespace(r.allowedNamespaces, namespace, r.cm.GetDefaultNamespace(kubeContextVal))
	if err != nil {
		return nil, err
	}

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.GetOptions{})

	// Execute
	return clientset.BatchV1().CronJobs(ns).Get(ctx, name, opts)
}

// BatchV1CronJobsList is the resolver for the batchV1CronJobsList field.
func (r *queryResolver) BatchV1CronJobsList(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (*batchv1.CronJobList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outList := &batchv1.CronJobList{}
	if err := r.listResource(ctx, kubeContextVal, namespace, options, outList); err != nil {
		return nil, err
	}

	return outList, nil
}

// BatchV1JobsGet is the resolver for the batchV1JobsGet field.
func (r *queryResolver) BatchV1JobsGet(ctx context.Context, kubeContext *string, namespace *string, name string, options *metav1.GetOptions) (*batchv1.Job, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Deref namespace
	ns, err := k8shelpers.DerefNamespace(r.allowedNamespaces, namespace, r.cm.GetDefaultNamespace(kubeContextVal))
	if err != nil {
		return nil, err
	}

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.GetOptions{})

	// Execute
	return clientset.BatchV1().Jobs(ns).Get(ctx, name, opts)
}

// BatchV1JobsList is the resolver for the batchV1JobsList field.
func (r *queryResolver) BatchV1JobsList(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (*batchv1.JobList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outList := &batchv1.JobList{}
	if err := r.listResource(ctx, kubeContextVal, namespace, options, outList); err != nil {
		return nil, err
	}

	return outList, nil
}

// CoreV1NamespacesList is the resolver for the coreV1NamespacesList field.
func (r *queryResolver) CoreV1NamespacesList(ctx context.Context, kubeContext *string, options *metav1.ListOptions) (*corev1.NamespaceList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.ListOptions{})

	response, err := clientset.CoreV1().Namespaces().List(ctx, opts)
	if err != nil {
		return response, nil
	}

	// apply app namespace filter
	if len(r.allowedNamespaces) > 0 {
		items := []corev1.Namespace{}
		for _, item := range response.Items {
			if slices.Contains(r.allowedNamespaces, item.Name) {
				items = append(items, item)
			}
		}
		response.Items = items
	}

	return response, err
}

// CoreV1NodesList is the resolver for the coreV1NodesList field.
func (r *queryResolver) CoreV1NodesList(ctx context.Context, kubeContext *string, options *metav1.ListOptions) (*corev1.NodeList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.ListOptions{})

	// Execute
	return clientset.CoreV1().Nodes().List(ctx, opts)
}

// CoreV1PodsGet is the resolver for the coreV1PodsGet field.
func (r *queryResolver) CoreV1PodsGet(ctx context.Context, kubeContext *string, namespace *string, name string, options *metav1.GetOptions) (*corev1.Pod, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Deref namespace
	ns, err := k8shelpers.DerefNamespace(r.allowedNamespaces, namespace, r.cm.GetDefaultNamespace(kubeContextVal))
	if err != nil {
		return nil, err
	}

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.GetOptions{})

	// Execute
	return clientset.CoreV1().Pods(ns).Get(ctx, name, opts)
}

// CoreV1PodsList is the resolver for the coreV1PodsList field.
func (r *queryResolver) CoreV1PodsList(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (*corev1.PodList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outList := &corev1.PodList{}
	if err := r.listResource(ctx, kubeContextVal, namespace, options, outList); err != nil {
		return nil, err
	}

	return outList, nil
}

// CoreV1ServicesGet is the resolver for the coreV1ServicesGet field.
func (r *queryResolver) CoreV1ServicesGet(ctx context.Context, kubeContext *string, namespace *string, name string, options *metav1.GetOptions) (*corev1.Service, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Deref namespace
	ns, err := k8shelpers.DerefNamespace(r.allowedNamespaces, namespace, r.cm.GetDefaultNamespace(kubeContextVal))
	if err != nil {
		return nil, err
	}

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.GetOptions{})

	// Execute
	return clientset.CoreV1().Services(ns).Get(ctx, name, opts)
}

// CoreV1ServicesList is the resolver for the coreV1ServicesList field.
func (r *queryResolver) CoreV1ServicesList(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (*corev1.ServiceList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outList := &corev1.ServiceList{}
	if err := r.listResource(ctx, kubeContextVal, namespace, options, outList); err != nil {
		return nil, err
	}

	return outList, nil
}

// ClusterAPIReadyWait is the resolver for the clusterAPIReadyWait field.
func (r *queryResolver) ClusterAPIReadyWait(ctx context.Context, kubeContext *string, namespace *string, serviceName *string) (bool, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	if err := r.hm.ReadyWait(ctx, kubeContextVal, namespace, serviceName); err != nil {
		return false, err
	}

	if ctx.Err() != nil {
		return false, ctx.Err()
	}

	return true, nil
}

// ClusterAPIHealthzGet is the resolver for the clusterAPIHealthzGet field.
func (r *queryResolver) ClusterAPIHealthzGet(ctx context.Context, kubeContext *string, namespace *string, serviceName *string) (*model.HealthCheckResponse, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	status, err := r.hm.GetHealthStatus(ctx, kubeContextVal, namespace, serviceName)
	if err != nil {
		return nil, err
	}

	return &model.HealthCheckResponse{
		Status:    healthCheckStatusFromClusterAPIHealthStatus(status),
		Timestamp: time.Now().UTC(),
	}, nil
}

// ClusterAPIServicesList is the resolver for the clusterAPIServicesList field.
func (r *queryResolver) ClusterAPIServicesList(ctx context.Context, kubeContext *string, options *metav1.ListOptions) (*corev1.ServiceList, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Reject requests not in desktop environment
	if r.environment != sharedcfg.EnvironmentDesktop {
		return nil, gqlerrors.ErrForbidden
	}

	// Restrict query to Cluster API services
	opts := ptr.Deref(options, metav1.ListOptions{})
	opts.LabelSelector = "app.kubernetes.io/name=kubetail,app.kubernetes.io/component=cluster-api"

	outList := &corev1.ServiceList{}
	if err := r.listResource(ctx, kubeContextVal, k8shelpers.BypassNamespaceCheck, &opts, outList); err != nil {
		return nil, err
	}

	return outList, nil
}

// HelmListReleases is the resolver for the helmListReleases field.
func (r *queryResolver) HelmListReleases(ctx context.Context, kubeContext *string) ([]*release.Release, error) {
	// Reject requests not in desktop environment
	if r.environment != sharedcfg.EnvironmentDesktop {
		return nil, gqlerrors.ErrForbidden
	}

	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Init client
	client := helm.NewClient(helm.WithKubeconfigPath(r.cfg.KubeconfigPath), helm.WithKubeContext(kubeContextVal))

	// Get list
	releases, err := client.ListReleases()
	if err != nil {
		return nil, err
	}

	return releases, nil
}

// CliLatestVersion is the resolver for the cliLatestVersion field.
func (r *queryResolver) CliLatestVersion(ctx context.Context) (*string, error) {
	if r.environment != sharedcfg.EnvironmentDesktop {
		return nil, nil
	}

	latestInfo, err := r.versionChecker.GetLatestCLIVersion()
	if err != nil {
		zlog.Warn().Err(err).Msg("Failed to check latest CLI version")
		return nil, nil
	}

	return &latestInfo.Version, nil
}

// ClusterVersionStatus is the resolver for the clusterVersionStatus field.
func (r *queryResolver) ClusterVersionStatus(ctx context.Context, kubeContext *string) (*model.VersionStatus, error) {
	var currentVersion string

	if r.environment == sharedcfg.EnvironmentDesktop {
		// Desktop mode: get the kubetail release from kubetail-system namespace for the active kubeContext
		kubeContextVal := r.cm.DerefKubeContext(kubeContext)
		rel, err := r.helmReleaseGetter.GetReleaseForContext(kubeContextVal, helm.DefaultNamespace, helm.DefaultReleaseName)
		if err != nil || rel == nil {
			return nil, nil
		}

		if rel.Chart != nil && rel.Chart.Metadata != nil {
			currentVersion = rel.Chart.Metadata.Version
		}
	} else {
		// Cluster mode: read chart version from environment variable
		currentVersion = os.Getenv("KUBETAIL_CHART_VERSION")
	}

	if currentVersion == "" {
		return nil, nil
	}

	latestInfo, err := r.versionChecker.GetLatestHelmChartVersion()
	if err != nil {
		zlog.Warn().Err(err).Msg("Failed to check latest Helm chart version")
		return nil, nil
	}

	currentSemver, err := semver.NewVersion(currentVersion)
	if err != nil {
		return nil, nil
	}

	latestSemver, err := semver.NewVersion(latestInfo.Version)
	if err != nil {
		return nil, nil
	}

	return &model.VersionStatus{
		CurrentVersion:  currentVersion,
		LatestVersion:   latestInfo.Version,
		UpdateAvailable: latestSemver.GreaterThan(currentSemver),
	}, nil
}

// KubeConfigGet is the resolver for the kubeConfigGet field.
func (r *queryResolver) KubeConfigGet(ctx context.Context) (*model.KubeConfig, error) {
	// Reject requests not in desktop environment
	if r.environment != sharedcfg.EnvironmentDesktop {
		return nil, gqlerrors.ErrForbidden
	}

	cm, ok := r.cm.(*k8shelpers.DesktopConnectionManager)
	if !ok {
		return nil, gqlerrors.ErrInternalServerError
	}

	return &model.KubeConfig{Config: cm.GetKubeConfig()}, nil
}

// KubernetesAPIReadyWait is the resolver for the kubernetesAPIReadyWait field.
func (r *queryResolver) KubernetesAPIReadyWait(ctx context.Context, kubeContext *string) (bool, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	ctx, cancel := context.WithTimeout(ctx, 20*time.Second)
	defer cancel()

	// Execute
	if err := r.cm.WaitUntilReady(ctx, kubeContextVal); err != nil {
		return false, err
	}

	return true, nil
}

// KubernetesAPIHealthzGet is the resolver for the kubernetesAPIHealthzGet field.
func (r *queryResolver) KubernetesAPIHealthzGet(ctx context.Context, kubeContext *string) (*model.HealthCheckResponse, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	return r.kubernetesAPIHealthzGet(ctx, kubeContextVal), nil
}

// LogRecordsFetch is the resolver for the logRecordsFetch field.
func (r *queryResolver) LogRecordsFetch(ctx context.Context, kubeContext *string, sources []string, mode *model.LogRecordsQueryMode, since *string, until *string, after *string, before *string, grep *string, sourceFilter *model.LogSourceFilter, limit *int) (*model.LogRecordsQueryResponse, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Parse time args
	sinceTime, err := parseTimeArg(ptr.Deref(since, ""))
	if err != nil {
		return nil, err
	}

	untilTime, err := parseTimeArg(ptr.Deref(until, ""))
	if err != nil {
		return nil, err
	}

	afterTime, err := parseTimeArg(ptr.Deref(after, ""))
	if err != nil {
		return nil, err
	}

	beforeTime, err := parseTimeArg(ptr.Deref(before, ""))
	if err != nil {
		return nil, err
	}

	// Handle after/before
	if !afterTime.IsZero() {
		sinceTime = afterTime.Add(1 * time.Nanosecond)
	}

	if !beforeTime.IsZero() {
		untilTime = beforeTime.Add(-1 * time.Nanosecond)
	}

	// Get bearer token
	var token string
	if tokenValue, ok := ctx.Value(k8shelpers.K8STokenCtxKey).(string); ok {
		token = tokenValue
	}

	// Init stream
	sourceFilterVal := ptr.Deref(sourceFilter, model.LogSourceFilter{})

	streamOpts := []logs.Option{
		logs.WithKubeContext(kubeContextVal),
		logs.WithBearerToken(token),
		logs.WithAllowedNamespaces(r.allowedNamespaces),
		logs.WithSince(sinceTime),
		logs.WithUntil(untilTime),
		logs.WithGrep(ptr.Deref(grep, "")),
		logs.WithRegions(sourceFilterVal.Region),
		logs.WithZones(sourceFilterVal.Zone),
		logs.WithOSes(sourceFilterVal.Os),
		logs.WithArches(sourceFilterVal.Arch),
		logs.WithNodes(sourceFilterVal.Node),
		logs.WithContainers(sourceFilterVal.Container),
	}

	modeVal := ptr.Deref(mode, model.LogRecordsQueryModeTail)
	limitVal := int64(ptr.Deref(limit, 100))
	effectiveLimit := limitVal
	if limitVal > 0 {
		// Fetch one extra record so we can compute nextCursor for the next page.
		effectiveLimit = limitVal + 1
	}

	switch modeVal {
	case model.LogRecordsQueryModeHead:
		streamOpts = append(streamOpts, logs.WithHead(effectiveLimit))
	case model.LogRecordsQueryModeTail:
		streamOpts = append(streamOpts, logs.WithTail(effectiveLimit))
	default:
		return nil, fmt.Errorf("not implemented %s", mode)
	}

	stream, err := logs.NewStream(ctx, r.cm, sources, streamOpts...)
	if err != nil {
		return nil, err
	}
	defer stream.Close()

	// Start stream
	if err := stream.Start(ctx); err != nil {
		return nil, err
	}

	// Write out records
	records := make([]logs.LogRecord, 0, int(effectiveLimit))
	for record := range stream.Records() {
		records = append(records, record)
	}

	// Apply pagination
	var paginationMode logs.PaginationMode
	if modeVal == model.LogRecordsQueryModeHead {
		paginationMode = logs.PaginationModeHead
	} else {
		paginationMode = logs.PaginationModeTail
	}
	records, nextCursor := logs.PaginateLogRecords(records, limitVal, paginationMode)

	outRecords := make([]*logs.LogRecord, 0, len(records))
	for i := range records {
		outRecords = append(outRecords, &records[i])
	}

	out := &model.LogRecordsQueryResponse{
		Records:    outRecords,
		NextCursor: nextCursor,
	}

	if ctx.Err() != nil {
		return nil, ctx.Err()
	}

	if stream.Err() != nil {
		return nil, stream.Err()
	}

	return out, nil
}

// AppsV1DaemonSetsWatch is the resolver for the appsV1DaemonSetsWatch field.
func (r *subscriptionResolver) AppsV1DaemonSetsWatch(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)
	gvr := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "daemonsets"}
	return r.watchResourceMulti(ctx, kubeContextVal, namespace, options, gvr)
}

// AppsV1DeploymentsWatch is the resolver for the appsV1DeploymentsWatch field.
func (r *subscriptionResolver) AppsV1DeploymentsWatch(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)
	gvr := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}
	return r.watchResourceMulti(ctx, kubeContextVal, namespace, options, gvr)
}

// AppsV1ReplicaSetsWatch is the resolver for the appsV1ReplicaSetsWatch field.
func (r *subscriptionResolver) AppsV1ReplicaSetsWatch(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)
	gvr := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "replicasets"}
	return r.watchResourceMulti(ctx, kubeContextVal, namespace, options, gvr)
}

// AppsV1StatefulSetsWatch is the resolver for the appsV1StatefulSetsWatch field.
func (r *subscriptionResolver) AppsV1StatefulSetsWatch(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)
	gvr := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "statefulsets"}
	return r.watchResourceMulti(ctx, kubeContextVal, namespace, options, gvr)
}

// BatchV1CronJobsWatch is the resolver for the batchV1CronJobsWatch field.
func (r *subscriptionResolver) BatchV1CronJobsWatch(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)
	gvr := schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "cronjobs"}
	return r.watchResourceMulti(ctx, kubeContextVal, namespace, options, gvr)
}

// BatchV1JobsWatch is the resolver for the batchV1JobsWatch field.
func (r *subscriptionResolver) BatchV1JobsWatch(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)
	gvr := schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "jobs"}
	return r.watchResourceMulti(ctx, kubeContextVal, namespace, options, gvr)
}

// CoreV1NamespacesWatch is the resolver for the coreV1NamespacesWatch field.
func (r *subscriptionResolver) CoreV1NamespacesWatch(ctx context.Context, kubeContext *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.ListOptions{})

	// Init watch
	watchAPI, err := clientset.CoreV1().Namespaces().Watch(ctx, opts)
	if err != nil {
		return nil, err
	}

	// Wrap proxy channel to remove namespaces that aren't allowed
	outCh := make(chan *watch.Event)
	go func() {
		for ev := range watchEventProxyChannel(ctx, watchAPI) {
			ns, err := typeassertRuntimeObject[*corev1.Namespace](ev.Object)
			if err != nil {
				transport.AddSubscriptionError(ctx, gqlerrors.ErrInternalServerError)
				break
			}

			// filter out non-authorized namespaces
			if len(r.allowedNamespaces) == 0 || (len(r.allowedNamespaces) > 0 && slices.Contains(r.allowedNamespaces, ns.Name)) {
				outCh <- ev
			}
		}
		close(outCh)
	}()

	return outCh, nil
}

// CoreV1NodesWatch is the resolver for the coreV1NodesWatch field.
func (r *subscriptionResolver) CoreV1NodesWatch(ctx context.Context, kubeContext *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Get client
	clientset, err := r.cm.GetOrCreateClientset(kubeContextVal)
	if err != nil {
		return nil, err
	}

	// Deref options
	opts := ptr.Deref(options, metav1.ListOptions{})

	// Init watch
	watchAPI, err := clientset.CoreV1().Nodes().Watch(ctx, opts)
	if err != nil {
		return nil, err
	}

	return watchEventProxyChannel(ctx, watchAPI), nil
}

// CoreV1PodsWatch is the resolver for the coreV1PodsWatch field.
func (r *subscriptionResolver) CoreV1PodsWatch(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)
	gvr := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
	return r.watchResourceMulti(ctx, kubeContextVal, namespace, options, gvr)
}

// CoreV1ServicesWatch is the resolver for the coreV1ServicesWatch field.
func (r *subscriptionResolver) CoreV1ServicesWatch(ctx context.Context, kubeContext *string, namespace *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)
	gvr := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "services"}
	return r.watchResourceMulti(ctx, kubeContextVal, namespace, options, gvr)
}

// KubernetesAPIReadyWait is the resolver for the kubernetesAPIReadyWait field.
func (r *subscriptionResolver) KubernetesAPIReadyWait(ctx context.Context, kubeContext *string) (<-chan bool, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outCh := make(chan bool)

	// Run in go routine
	go func() {
		defer close(outCh)
		if err := r.cm.WaitUntilReady(ctx, kubeContextVal); err != nil {
			transport.AddSubscriptionError(ctx, gqlerrors.ErrInternalServerError)
			return
		}
		outCh <- true
	}()

	return outCh, nil
}

// KubernetesAPIHealthzWatch is the resolver for the kubernetesAPIHealthzWatch field.
func (r *subscriptionResolver) KubernetesAPIHealthzWatch(ctx context.Context, kubeContext *string) (<-chan *model.HealthCheckResponse, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outCh := make(chan *model.HealthCheckResponse)

	go func() {
		var lastResponse *model.HealthCheckResponse
		ticker := time.NewTicker(3 * time.Second)

		resp := r.kubernetesAPIHealthzGet(ctx, kubeContextVal)
		lastResponse = resp
		outCh <- resp

	Loop:
		for {
			select {
			case <-ctx.Done():
				// listener closed connection
				break Loop
			case <-ticker.C:
				resp := r.kubernetesAPIHealthzGet(ctx, kubeContextVal)
				if lastResponse.Status != resp.Status || !ptr.Equal(lastResponse.Message, resp.Message) {
					lastResponse = resp
					outCh <- resp
				}
			}
		}

		// cleanup
		ticker.Stop()
		close(outCh)
	}()

	return outCh, nil
}

// ClusterAPIReadyWait is the resolver for the clusterAPIReadyWait field.
func (r *subscriptionResolver) ClusterAPIReadyWait(ctx context.Context, kubeContext *string, namespace *string, serviceName *string) (<-chan bool, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	outCh := make(chan bool)

	// Run in go routine
	go func() {
		defer close(outCh)

		if err := r.hm.ReadyWait(ctx, kubeContextVal, namespace, serviceName); err != nil {
			transport.AddSubscriptionError(ctx, gqlerrors.ErrInternalServerError)
			return
		}

		outCh <- true
	}()

	return outCh, nil
}

// ClusterAPIHealthzWatch is the resolver for the clusterAPIHealthzWatch field.
func (r *subscriptionResolver) ClusterAPIHealthzWatch(ctx context.Context, kubeContext *string, namespace *string, serviceName *string) (<-chan *model.HealthCheckResponse, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	statusCh, err := r.hm.WatchHealthStatus(ctx, kubeContextVal, namespace, serviceName)
	if err != nil {
		return nil, err
	}

	outCh := make(chan *model.HealthCheckResponse)

	// Run in go routine
	go func() {
		defer close(outCh)

		for status := range statusCh {
			resp := &model.HealthCheckResponse{
				Status:    healthCheckStatusFromClusterAPIHealthStatus(status),
				Timestamp: time.Now().UTC(),
			}
			outCh <- resp
		}
	}()

	return outCh, nil
}

// ClusterAPIServicesWatch is the resolver for the clusterAPIServicesWatch field.
func (r *subscriptionResolver) ClusterAPIServicesWatch(ctx context.Context, kubeContext *string, options *metav1.ListOptions) (<-chan *watch.Event, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Reject requests not in desktop environment
	if r.environment != sharedcfg.EnvironmentDesktop {
		return nil, gqlerrors.ErrForbidden
	}

	// Restrict query
	opts := ptr.Deref(options, metav1.ListOptions{})
	opts.LabelSelector = "app.kubernetes.io/name=kubetail,app.kubernetes.io/component=cluster-api"

	gvr := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "services"}
	return r.watchResourceMulti(ctx, kubeContextVal, k8shelpers.BypassNamespaceCheck, &opts, gvr)
}

// KubeConfigWatch is the resolver for the kubeConfigWatch field.
func (r *subscriptionResolver) KubeConfigWatch(ctx context.Context) (<-chan *model.KubeConfigWatchEvent, error) {
	// Reject requests not in desktop environment
	if r.environment != sharedcfg.EnvironmentDesktop {
		return nil, gqlerrors.ErrForbidden
	}

	cm, ok := r.cm.(*k8shelpers.DesktopConnectionManager)
	if !ok {
		return nil, gqlerrors.ErrInternalServerError
	}

	// Init output channel
	outCh := make(chan *model.KubeConfigWatchEvent)

	go func() {
		defer close(outCh)

		// Send initial config
		ev := &model.KubeConfigWatchEvent{
			Type:   watch.Added,
			Object: &model.KubeConfig{Config: cm.GetKubeConfig()},
		}
		select {
		case <-ctx.Done():
			return
		case outCh <- ev:
		}

		// Register callback handler
		sub, err := cm.KubeConfigWatcher.Subscribe(func(newConfig *api.Config) {
			// Send MODIFIED event
			ev := &model.KubeConfigWatchEvent{
				Type:   watch.Modified,
				Object: &model.KubeConfig{Config: newConfig},
			}
			select {
			case <-ctx.Done():
			case outCh <- ev:
			}
		})
		if err != nil {
			return
		}

		defer sub.Drain()

		// Wait for client close
		<-ctx.Done()
	}()

	return outCh, nil
}

// LogRecordsFollow is the resolver for the logRecordsFollow field.
func (r *subscriptionResolver) LogRecordsFollow(ctx context.Context, kubeContext *string, sources []string, since *string, after *string, grep *string, sourceFilter *model.LogSourceFilter) (<-chan *logs.LogRecord, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	// Parse time args
	sinceTime, err := parseTimeArg(ptr.Deref(since, ""))
	if err != nil {
		return nil, err
	}

	afterTime, err := parseTimeArg(ptr.Deref(after, ""))
	if err != nil {
		return nil, err
	}

	// Handle after/before
	if !afterTime.IsZero() {
		sinceTime = afterTime.Add(1 * time.Nanosecond)
	}

	// Get bearer token
	var token string
	if tokenValue, ok := ctx.Value(k8shelpers.K8STokenCtxKey).(string); ok {
		token = tokenValue
	}

	// Init stream
	sourceFilterVal := ptr.Deref(sourceFilter, model.LogSourceFilter{})

	streamOpts := []logs.Option{
		logs.WithKubeContext(kubeContextVal),
		logs.WithBearerToken(token),
		logs.WithAllowedNamespaces(r.allowedNamespaces),
		logs.WithAll(),
		logs.WithFollow(true),
		logs.WithSince(sinceTime),
		logs.WithGrep(ptr.Deref(grep, "")),
		logs.WithRegions(sourceFilterVal.Region),
		logs.WithZones(sourceFilterVal.Zone),
		logs.WithOSes(sourceFilterVal.Os),
		logs.WithArches(sourceFilterVal.Arch),
		logs.WithNodes(sourceFilterVal.Node),
		logs.WithContainers(sourceFilterVal.Container),
	}

	stream, err := logs.NewStream(ctx, r.cm, sources, streamOpts...)
	if err != nil {
		return nil, err
	}

	// Start stream
	if err := stream.Start(ctx); err != nil {
		return nil, err
	}

	// Init output channel
	outCh := make(chan *logs.LogRecord)

	// Write out in goroutine
	go func() {
		defer close(outCh)
		defer stream.Close()

		for record := range stream.Records() {
			select {
			case <-ctx.Done():
				return
			case outCh <- &record:
				// Success
			}
		}

		// Handle errors
		if stream.Err() != nil {
			// Log the error on the server, including caller info as requested.
			zlog.Error().Err(stream.Err()).Caller().Send()

			// If the client connection is still open, let it know that there was an upstream error.
			transport.AddSubscriptionError(ctx, gqlerrors.ErrInternalServerError)
		}
	}()

	return outCh, nil
}

// LogSourcesWatch is the resolver for the logSourcesWatch field.
func (r *subscriptionResolver) LogSourcesWatch(ctx context.Context, kubeContext *string, sources []string) (<-chan *model.LogSourceWatchEvent, error) {
	kubeContextVal := r.cm.DerefKubeContext(kubeContext)

	var token string
	if tokenValue, ok := ctx.Value(k8shelpers.K8STokenCtxKey).(string); ok {
		token = tokenValue
	}

	sw, err := logs.NewSourceWatcher(r.cm, sources, logs.WithKubeContext(kubeContextVal), logs.WithBearerToken(token))
	if err != nil {
		return nil, err
	}

	outCh := make(chan *model.LogSourceWatchEvent)

	// Start source watcher
	go func() {
		defer close(outCh)

		// Handle ADD events
		_, err := sw.Subscribe(logs.SourceWatcherEventAdded, func(source logs.LogSource) {
			ev := &model.LogSourceWatchEvent{
				Type:   watch.Added,
				Object: &source,
			}

			select {
			case <-ctx.Done():
			case outCh <- ev:
			}
		})
		if err != nil {
			return
		}

		// Handle DELETE events
		_, err = sw.Subscribe(logs.SourceWatcherEventDeleted, func(source logs.LogSource) {
			ev := &model.LogSourceWatchEvent{
				Type:   watch.Deleted,
				Object: &source,
			}

			select {
			case <-ctx.Done():
				return
			case outCh <- ev:
			}
		})
		if err != nil {
			return
		}

		// Start source watcher
		if err := sw.Start(ctx); err != nil {
			transport.AddSubscriptionError(ctx, gqlerrors.ErrInternalServerError)
			return
		}

		// Close source watcher on client close
		defer sw.Close()

		// Wait for client close
		<-ctx.Done()
	}()

	return outCh, nil
}

// AppsV1DaemonSetsWatchEvent returns AppsV1DaemonSetsWatchEventResolver implementation.
func (r *Resolver) AppsV1DaemonSetsWatchEvent() AppsV1DaemonSetsWatchEventResolver {
	return &appsV1DaemonSetsWatchEventResolver{r}
}

// AppsV1DeploymentsWatchEvent returns AppsV1DeploymentsWatchEventResolver implementation.
func (r *Resolver) AppsV1DeploymentsWatchEvent() AppsV1DeploymentsWatchEventResolver {
	return &appsV1DeploymentsWatchEventResolver{r}
}

// AppsV1ReplicaSetsWatchEvent returns AppsV1ReplicaSetsWatchEventResolver implementation.
func (r *Resolver) AppsV1ReplicaSetsWatchEvent() AppsV1ReplicaSetsWatchEventResolver {
	return &appsV1ReplicaSetsWatchEventResolver{r}
}

// AppsV1StatefulSetsWatchEvent returns AppsV1StatefulSetsWatchEventResolver implementation.
func (r *Resolver) AppsV1StatefulSetsWatchEvent() AppsV1StatefulSetsWatchEventResolver {
	return &appsV1StatefulSetsWatchEventResolver{r}
}

// BatchV1CronJobsWatchEvent returns BatchV1CronJobsWatchEventResolver implementation.
func (r *Resolver) BatchV1CronJobsWatchEvent() BatchV1CronJobsWatchEventResolver {
	return &batchV1CronJobsWatchEventResolver{r}
}

// BatchV1JobsWatchEvent returns BatchV1JobsWatchEventResolver implementation.
func (r *Resolver) BatchV1JobsWatchEvent() BatchV1JobsWatchEventResolver {
	return &batchV1JobsWatchEventResolver{r}
}

// CoreV1NamespacesWatchEvent returns CoreV1NamespacesWatchEventResolver implementation.
func (r *Resolver) CoreV1NamespacesWatchEvent() CoreV1NamespacesWatchEventResolver {
	return &coreV1NamespacesWatchEventResolver{r}
}

// CoreV1NodesWatchEvent returns CoreV1NodesWatchEventResolver implementation.
func (r *Resolver) CoreV1NodesWatchEvent() CoreV1NodesWatchEventResolver {
	return &coreV1NodesWatchEventResolver{r}
}

// CoreV1PodsWatchEvent returns CoreV1PodsWatchEventResolver implementation.
func (r *Resolver) CoreV1PodsWatchEvent() CoreV1PodsWatchEventResolver {
	return &coreV1PodsWatchEventResolver{r}
}

// CoreV1ServicesWatchEvent returns CoreV1ServicesWatchEventResolver implementation.
func (r *Resolver) CoreV1ServicesWatchEvent() CoreV1ServicesWatchEventResolver {
	return &coreV1ServicesWatchEventResolver{r}
}

// KubeConfig returns KubeConfigResolver implementation.
func (r *Resolver) KubeConfig() KubeConfigResolver { return &kubeConfigResolver{r} }

// Mutation returns MutationResolver implementation.
func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }

// Query returns QueryResolver implementation.
func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }

// Subscription returns SubscriptionResolver implementation.
func (r *Resolver) Subscription() SubscriptionResolver { return &subscriptionResolver{r} }

type appsV1DaemonSetsWatchEventResolver struct{ *Resolver }
type appsV1DeploymentsWatchEventResolver struct{ *Resolver }
type appsV1ReplicaSetsWatchEventResolver struct{ *Resolver }
type appsV1StatefulSetsWatchEventResolver struct{ *Resolver }
type batchV1CronJobsWatchEventResolver struct{ *Resolver }
type batchV1JobsWatchEventResolver struct{ *Resolver }
type coreV1NamespacesWatchEventResolver struct{ *Resolver }
type coreV1NodesWatchEventResolver struct{ *Resolver }
type coreV1PodsWatchEventResolver struct{ *Resolver }
type coreV1ServicesWatchEventResolver struct{ *Resolver }
type kubeConfigResolver struct{ *Resolver }
type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
type subscriptionResolver struct{ *Resolver }
