//
// This file is generated by grafana-app-sdk
// DO NOT EDIT
//

package manifestdata

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/grafana/grafana-app-sdk/app"
	"github.com/grafana/grafana-app-sdk/resource"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/kube-openapi/pkg/spec3"
	"k8s.io/kube-openapi/pkg/validation/spec"

	v1 "codegen-tests/pkg/generated/testapp/v1"
	v2 "codegen-tests/pkg/generated/testapp/v2"
	v3 "codegen-tests/pkg/generated/testapp/v3"
	v4 "codegen-tests/pkg/generated/testapp/v4"
)

var (
	rawSchemaTestKindv1      = []byte(`{"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":true,"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"TestKind":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"spec":{"additionalProperties":false,"properties":{"stringField":{"pattern":"^[a-zA-Z_][a-zA-Z0-9_-]*$","type":"string"}},"required":["stringField"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":true,"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
	versionSchemaTestKindv1  app.VersionSchema
	_                        = json.Unmarshal(rawSchemaTestKindv1, &versionSchemaTestKindv1)
	rawSchemaTestKind2v1     = []byte(`{"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":true,"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"TestKind2":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"spec":{"additionalProperties":false,"properties":{"testField":{"type":"string"}},"required":["testField"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":true,"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
	versionSchemaTestKind2v1 app.VersionSchema
	_                        = json.Unmarshal(rawSchemaTestKind2v1, &versionSchemaTestKind2v1)
	rawSchemaTestKindv2      = []byte(`{"Def":{"additionalProperties":false,"properties":{"i":{"type":"integer"},"str":{"type":"string"}},"required":["str","i"],"type":"object"},"Def2":{"additionalProperties":false,"properties":{"b":{"type":"boolean"},"str":{"type":"string"}},"required":["str","b"],"type":"object"},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":true,"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"TestKind":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"spec":{"additionalProperties":false,"properties":{"intField":{"type":"integer"},"stringField":{"type":"string"},"timeField":{"format":"date-time","type":"string"},"unionNull":{"allOf":[{"$ref":"#/components/schemas/Def"}],"description":"This generates a normal go pointer field, but needs to be handled correctly as a selectable field, as the schema logic registers it as a disjunction","nullable":true},"unionNull2":{"description":"null variant should be ignore in disjunction when generating the selectable field","oneOf":[{"$ref":"#/components/schemas/Def"},{"$ref":"#/components/schemas/Def2"},{"type":"null"}]}},"required":["stringField","intField","timeField"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":true,"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
	versionSchemaTestKindv2  app.VersionSchema
	_                        = json.Unmarshal(rawSchemaTestKindv2, &versionSchemaTestKindv2)
	rawSchemaTestKindv3      = []byte(`{"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":true,"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"TestKind":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"spec":{"additionalProperties":false,"properties":{"boolField":{"type":"boolean"},"intField":{"type":"integer"},"stringField":{"type":"string"},"timeField":{"format":"date-time","type":"string"}},"required":["stringField","intField","timeField","boolField"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":true,"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
	versionSchemaTestKindv3  app.VersionSchema
	_                        = json.Unmarshal(rawSchemaTestKindv3, &versionSchemaTestKindv3)
	rawSchemaTestKindv4      = []byte(`{"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":true,"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"TestKind":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"UnionVariantA":{"additionalProperties":false,"properties":{"kind":{"const":"VariantA","type":"string"},"spec":{"additionalProperties":false,"properties":{"name":{"type":"string"}},"required":["name"],"type":"object"}},"required":["kind","spec"],"type":"object"},"UnionVariantB":{"additionalProperties":false,"properties":{"kind":{"const":"VariantB","type":"string"},"spec":{"additionalProperties":false,"properties":{"name":{"type":"string"}},"required":["name"],"type":"object"}},"required":["kind","spec"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"union":{"oneOf":[{"$ref":"#/components/schemas/UnionVariantA"},{"$ref":"#/components/schemas/UnionVariantB"}]}},"required":["union"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":true,"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
	versionSchemaTestKindv4  app.VersionSchema
	_                        = json.Unmarshal(rawSchemaTestKindv4, &versionSchemaTestKindv4)
)

var appManifestData = app.ManifestData{
	AppName:          "test-app",
	AppDisplayName:   "test-app",
	Group:            "testapp.ext.grafana.app",
	PreferredVersion: "v1",
	Versions: []app.ManifestVersion{
		{
			Name:   "v1",
			Served: true,
			Kinds: []app.ManifestVersionKind{
				{
					Kind:       "TestKind",
					Plural:     "TestKinds",
					Scope:      "Namespaced",
					Conversion: true,
					Admission: &app.AdmissionCapabilities{
						Validation: &app.ValidationCapability{
							Operations: []app.AdmissionOperation{
								app.AdmissionOperationCreate,
								app.AdmissionOperationUpdate,
							},
						},
					},
					Schema: &versionSchemaTestKindv1,
					SelectableFields: []string{
						".spec.stringField",
					},
					SearchFields: []app.ManifestVersionKindSearchField{
						{
							Name:         "stringField",
							Path:         "spec.stringField",
							Type:         "string",
							Capabilities: []string{"filter", "text", "sort", "retrieve"},
							Description:  "The string field",
						},
					},
				},

				{
					Kind:       "TestKind2",
					Plural:     "TestKind2s",
					Scope:      "Namespaced",
					Conversion: false,
					Schema:     &versionSchemaTestKind2v1,
				},
			},
			Routes: app.ManifestVersionRoutes{
				Namespaced: map[string]spec3.PathProps{},
				Cluster:    map[string]spec3.PathProps{},
				Schemas:    map[string]spec.Schema{},
			},
		},

		{
			Name:   "v2",
			Served: true,
			Kinds: []app.ManifestVersionKind{
				{
					Kind:       "TestKind",
					Plural:     "TestKinds",
					Scope:      "Namespaced",
					Conversion: true,
					Admission: &app.AdmissionCapabilities{
						Validation: &app.ValidationCapability{
							Operations: []app.AdmissionOperation{
								app.AdmissionOperationCreate,
								app.AdmissionOperationUpdate,
							},
						},
						Mutation: &app.MutationCapability{
							Operations: []app.AdmissionOperation{
								app.AdmissionOperationCreate,
								app.AdmissionOperationUpdate,
							},
						},
					},
					Schema: &versionSchemaTestKindv2,
					SelectableFields: []string{
						".spec.stringField",
						".spec.intField",
						".spec.unionNull.str",
						".spec.unionNull2.str",
					},
					SearchFields: []app.ManifestVersionKindSearchField{
						{
							Name:         "stringField",
							Path:         "spec.stringField",
							Type:         "string",
							Capabilities: []string{"filter", "text", "sort", "retrieve"},
							Description:  "The string field",
						},
						{
							Name:             "intField",
							Path:             "spec.intField",
							Type:             "int64",
							Capabilities:     []string{"filter", "retrieve"},
							EmitZeroIfAbsent: true,
						},
					},
				},
			},
			Routes: app.ManifestVersionRoutes{
				Namespaced: map[string]spec3.PathProps{},
				Cluster:    map[string]spec3.PathProps{},
				Schemas:    map[string]spec.Schema{},
			},
		},

		{
			Name:   "v3",
			Served: true,
			Kinds: []app.ManifestVersionKind{
				{
					Kind:       "TestKind",
					Plural:     "TestKinds",
					Scope:      "Namespaced",
					Conversion: true,
					Admission: &app.AdmissionCapabilities{
						Validation: &app.ValidationCapability{
							Operations: []app.AdmissionOperation{
								app.AdmissionOperationCreate,
								app.AdmissionOperationUpdate,
							},
						},
						Mutation: &app.MutationCapability{
							Operations: []app.AdmissionOperation{
								app.AdmissionOperationCreate,
								app.AdmissionOperationUpdate,
							},
						},
					},
					Schema: &versionSchemaTestKindv3,
					SelectableFields: []string{
						".spec.stringField",
						".spec.intField",
						".spec.boolField",
					},
					SearchFields: []app.ManifestVersionKindSearchField{
						{
							Name:         "stringField",
							Path:         "spec.stringField",
							Type:         "string",
							Capabilities: []string{"filter", "text", "sort", "retrieve"},
							Description:  "The string field",
						},
						{
							Name:             "intField",
							Path:             "spec.intField",
							Type:             "int64",
							Capabilities:     []string{"filter", "retrieve"},
							EmitZeroIfAbsent: true,
						},
						{
							Name:             "boolField",
							Path:             "spec.boolField",
							Type:             "boolean",
							Capabilities:     []string{"filter", "retrieve"},
							EmitZeroIfAbsent: true,
						},
					},
					Routes: map[string]spec3.PathProps{
						"/reconcile": {
							Post: &spec3.Operation{
								OperationProps: spec3.OperationProps{

									OperationId: "createReconcileRequest",

									RequestBody: &spec3.RequestBody{
										RequestBodyProps: spec3.RequestBodyProps{

											Required: true,
											Content: map[string]*spec3.MediaType{
												"application/json": {
													MediaTypeProps: spec3.MediaTypeProps{
														Schema: &spec.Schema{
															SchemaProps: spec.SchemaProps{
																Type: []string{"object"},
																Properties: map[string]spec.Schema{
																	"force": {
																		SchemaProps: spec.SchemaProps{
																			Type: []string{"boolean"},
																		},
																	},
																	"reason": {
																		SchemaProps: spec.SchemaProps{
																			Type: []string{"string"},
																		},
																	},
																},
																Required: []string{
																	"force",
																},
															}},
													}},
											},
										}},
									Responses: &spec3.Responses{
										ResponsesProps: spec3.ResponsesProps{
											Default: &spec3.Response{
												ResponseProps: spec3.ResponseProps{
													Description: "Default OK response",
													Content: map[string]*spec3.MediaType{
														"application/json": {
															MediaTypeProps: spec3.MediaTypeProps{
																Schema: &spec.Schema{
																	SchemaProps: spec.SchemaProps{
																		Type: []string{"object"},
																		Properties: map[string]spec.Schema{
																			"message": {
																				SchemaProps: spec.SchemaProps{
																					Type:        []string{"string"},
																					Description: "A comment containing \"quotes\" should not break anything",
																				},
																			},
																			"status": {
																				SchemaProps: spec.SchemaProps{
																					Type: []string{"string"},
																					Enum: []interface{}{
																						"success",
																						"failure",
																					},
																				},
																			},
																		},
																		Required: []string{
																			"status",
																			"message",
																		},
																	}},
															}},
													},
												},
											},
										}},
								},
							},
						},
						"/search": {
							Get: &spec3.Operation{
								OperationProps: spec3.OperationProps{

									OperationId: "getTestKindSearchResult",

									Parameters: []*spec3.Parameter{

										{
											ParameterProps: spec3.ParameterProps{
												Name: "limit",
												In:   "query",
												Schema: &spec.Schema{
													SchemaProps: spec.SchemaProps{
														Type: []string{"integer"},
													},
												},
											},
										},

										{
											ParameterProps: spec3.ParameterProps{
												Name: "offset",
												In:   "query",
												Schema: &spec.Schema{
													SchemaProps: spec.SchemaProps{
														Type: []string{"integer"},
													},
												},
											},
										},

										{
											ParameterProps: spec3.ParameterProps{
												Name:     "q",
												In:       "query",
												Required: true,
												Schema: &spec.Schema{
													SchemaProps: spec.SchemaProps{
														Type: []string{"string"},
													},
												},
											},
										},
									},

									Responses: &spec3.Responses{
										ResponsesProps: spec3.ResponsesProps{
											Default: &spec3.Response{
												ResponseProps: spec3.ResponseProps{
													Description: "Default OK response",
													Content: map[string]*spec3.MediaType{
														"application/json": {
															MediaTypeProps: spec3.MediaTypeProps{
																Schema: &spec.Schema{
																	SchemaProps: spec.SchemaProps{
																		Type: []string{"object"},
																		Properties: map[string]spec.Schema{
																			"apiVersion": {
																				SchemaProps: spec.SchemaProps{
																					Type:        []string{"string"},
																					Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
																				},
																			},
																			"items": {
																				SchemaProps: spec.SchemaProps{
																					Type: []string{"array"},
																					Items: &spec.SchemaOrArray{
																						Schema: &spec.Schema{
																							SchemaProps: spec.SchemaProps{
																								Type: []string{"object"},
																								Properties: map[string]spec.Schema{
																									"list": {
																										SchemaProps: spec.SchemaProps{
																											Type: []string{"array"},
																											Items: &spec.SchemaOrArray{
																												Schema: &spec.Schema{
																													SchemaProps: spec.SchemaProps{
																														Type: []string{"object"},
																														Properties: map[string]spec.Schema{
																															"foo": {
																																SchemaProps: spec.SchemaProps{
																																	Type: []string{"string"},
																																},
																															},
																														},
																														Required: []string{
																															"foo",
																														},
																													}},
																											},
																										},
																									},
																									"name": {
																										SchemaProps: spec.SchemaProps{
																											Type: []string{"string"},
																										},
																									},
																									"score": {
																										SchemaProps: spec.SchemaProps{
																											Type: []string{"number"},
																										},
																									},
																								},
																								Required: []string{
																									"name",
																									"score",
																									"list",
																								},
																							}},
																					},
																				},
																			},
																			"kind": {
																				SchemaProps: spec.SchemaProps{
																					Type:        []string{"string"},
																					Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
																				},
																			},
																			"total": {
																				SchemaProps: spec.SchemaProps{
																					Type: []string{"integer"},
																				},
																			},
																		},
																		Required: []string{
																			"items",
																			"total",
																			"apiVersion",
																			"kind",
																		},
																	}},
															}},
													},
												},
											},
										}},
								},
								VendorExtensible: spec.VendorExtensible{
									Extensions: spec.Extensions{
										"x-grafana-test":       true,
										"x-grafana-test-value": map[string]interface{}{"val": "1"},
									},
								},
							},
						},
					},
				},
			},
			Routes: app.ManifestVersionRoutes{
				Namespaced: map[string]spec3.PathProps{
					"/foobar": {
						Post: &spec3.Operation{
							OperationProps: spec3.OperationProps{

								OperationId: "createFoobar",

								RequestBody: &spec3.RequestBody{
									RequestBodyProps: spec3.RequestBodyProps{

										Required: true,
										Content: map[string]*spec3.MediaType{
											"application/json": {
												MediaTypeProps: spec3.MediaTypeProps{
													Schema: &spec.Schema{
														SchemaProps: spec.SchemaProps{
															Type: []string{"object"},
															Properties: map[string]spec.Schema{
																"keys": {
																	SchemaProps: spec.SchemaProps{
																		Type: []string{"array"},
																		Items: &spec.SchemaOrArray{
																			Schema: &spec.Schema{
																				SchemaProps: spec.SchemaProps{

																					Ref: spec.MustCreateRef("#/components/schemas/createFoobarKey"),
																				}},
																		},
																	},
																},
															},
															Required: []string{
																"keys",
															},
														}},
												}},
										},
									}},
								Responses: &spec3.Responses{
									ResponsesProps: spec3.ResponsesProps{
										Default: &spec3.Response{
											ResponseProps: spec3.ResponseProps{
												Description: "Default OK response",
												Content: map[string]*spec3.MediaType{
													"application/json": {
														MediaTypeProps: spec3.MediaTypeProps{
															Schema: &spec.Schema{
																SchemaProps: spec.SchemaProps{
																	Type: []string{"object"},
																	Properties: map[string]spec.Schema{
																		"altered": {
																			SchemaProps: spec.SchemaProps{
																				Type: []string{"array"},
																				Items: &spec.SchemaOrArray{
																					Schema: &spec.Schema{
																						SchemaProps: spec.SchemaProps{

																							Ref: spec.MustCreateRef("#/components/schemas/createFoobarKey"),
																						}},
																				},
																			},
																		},
																		"apiVersion": {
																			SchemaProps: spec.SchemaProps{
																				Type:        []string{"string"},
																				Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
																			},
																		},
																		"kind": {
																			SchemaProps: spec.SchemaProps{
																				Type:        []string{"string"},
																				Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
																			},
																		},
																	},
																	Required: []string{
																		"altered",
																		"apiVersion",
																		"kind",
																	},
																}},
														}},
												},
											},
										},
									}},
							},
						},
					},
				},
				Cluster: map[string]spec3.PathProps{},
				Schemas: map[string]spec.Schema{
					"createFoobarKey": {
						SchemaProps: spec.SchemaProps{
							Type:        []string{"object"},
							Description: "Key identifies a foobar entry.\nIt is referenced by a custom route, so its multi-line\ndescription exercises the route schema codegen path.",
							Properties: map[string]spec.Schema{
								"match": {
									SchemaProps: spec.SchemaProps{
										Type: []string{"string"},
									},
								},
								"name": {
									SchemaProps: spec.SchemaProps{
										Type: []string{"string"},
									},
								},
							},
							Required: []string{
								"name",
							},
						},
					},
				},
			},
		},

		{
			Name:   "v4",
			Served: true,
			Kinds: []app.ManifestVersionKind{
				{
					Kind:       "TestKind",
					Plural:     "TestKinds",
					Scope:      "Namespaced",
					Conversion: true,
					Admission: &app.AdmissionCapabilities{
						Validation: &app.ValidationCapability{
							Operations: []app.AdmissionOperation{
								app.AdmissionOperationCreate,
								app.AdmissionOperationUpdate,
							},
						},
					},
					Schema: &versionSchemaTestKindv4,
					SelectableFields: []string{
						".spec.union.spec.name",
					},
				},
			},
			Routes: app.ManifestVersionRoutes{
				Namespaced: map[string]spec3.PathProps{},
				Cluster:    map[string]spec3.PathProps{},
				Schemas:    map[string]spec.Schema{},
			},
		},
	},
	ExtraPermissions: &app.Permissions{
		AccessKinds: []app.KindPermission{
			{
				Group:    "foo.bar",
				Resource: "foos",
				Actions: []app.KindPermissionAction{
					"get",
					"list",
					"watch",
				},
			},
		},
	},
	Operator: &app.ManifestOperatorInfo{
		URL: "https://foo.bar:8443",
		Webhooks: &app.ManifestOperatorWebhookProperties{
			ConversionPath: "/convert",
			ValidationPath: "/validate",
			MutationPath:   "/mutate",
		},
	},
	Roles: map[string]app.ManifestRole{
		"test-app:reader": {
			Title:       "Test App Viewer",
			Description: "View Test App Resources",
			Kinds: []app.ManifestRoleKind{
				{
					Kind:          "TestKind",
					PermissionSet: strPtr("viewer"),
				},
			},
			Routes: []string{
				"createFoobar",
			},
		},
	},
	RoleBindings: &app.ManifestRoleBindings{
		Viewer: []string{
			"test-app:reader",
		},
		Editor: []string{},
		Admin:  []string{},
	},
}

func LocalManifest() app.Manifest {
	return app.NewEmbeddedManifest(appManifestData)
}

func RemoteManifest() app.Manifest {
	return app.NewAPIServerManifest("test-app")
}

var kindVersionToGoType = map[string]resource.Kind{
	"TestKind/v1":  v1.TestKindKind(),
	"TestKind2/v1": v1.TestKind2Kind(),
	"TestKind/v2":  v2.TestKindKind(),
	"TestKind/v3":  v3.TestKindKind(),
	"TestKind/v4":  v4.TestKindKind(),
}

// ManifestGoTypeAssociator returns the associated resource.Kind instance for a given Kind and Version, if one exists.
// If there is no association for the provided Kind and Version, exists will return false.
func ManifestGoTypeAssociator(kind, version string) (goType resource.Kind, exists bool) {
	goType, exists = kindVersionToGoType[fmt.Sprintf("%s/%s", kind, version)]
	return goType, exists
}

var customRouteToGoResponseType = map[string]any{

	"v3|TestKind|reconcile|POST": v3.CreateReconcileRequestResponse{},

	"v3|TestKind|search|GET": v3.GetTestKindSearchResultResponse{},

	"v3||<namespace>/foobar|POST": v3.CreateFoobarResponse{},
}

// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
// Resource routes (those without a kind) should prefix their route with "<namespace>/" if the route is namespaced (otherwise the route is assumed to be cluster-scope)
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
	if len(path) > 0 && path[0] == '/' {
		path = path[1:]
	}
	goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
	return goType, exists
}

var customRouteToGoParamsType = map[string]runtime.Object{

	"v3|TestKind|search|GET": &v3.GetTestKindSearchResultRequestParamsObject{},
}

func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goType runtime.Object, exists bool) {
	if len(path) > 0 && path[0] == '/' {
		path = path[1:]
	}
	goType, exists = customRouteToGoParamsType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
	return goType, exists
}

var customRouteToGoRequestBodyType = map[string]any{

	"v3|TestKind|reconcile|POST": &v3.CreateReconcileRequestRequestBody{},

	"v3||<namespace>/foobar|POST": v3.CreateFoobarRequestBody{},
}

func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) {
	if len(path) > 0 && path[0] == '/' {
		path = path[1:]
	}
	goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
	return goType, exists
}

type GoTypeAssociator struct{}

func NewGoTypeAssociator() *GoTypeAssociator {
	return &GoTypeAssociator{}
}

func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
	return ManifestGoTypeAssociator(kind, version)
}
func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb string) (goType any, exists bool) {
	return ManifestCustomRouteResponsesAssociator(kind, version, path, verb)
}
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
	return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
}
func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) {
	return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb)
}
func strPtr(s string) *string {
	return &s
}
