# Test that cyclic error formatting doesn't cause stack overflow.
# The combination of error() with self interpolation and complex nested
# struct patterns can cause infinite recursion when formatting error messages.
# https://cuelang.org/issue/4228
-- in.cue --
package main

_objectBase: self={
	name: string
	k8s: metadata: name: self.name
}

_namespacedResource: self={
	_objectBase
	namespace: string
	k8s: metadata: namespace: self.namespace
}

// Key validation pattern with error() and self
_allValuesAreValidStructs: [_]: self={
	*{} | error("<- invalid \(self)")
}

_setTypeMeta: self={
	#apiVersion!: string
	#kind!: string
	#template: k8s: {
		apiVersion: self.#apiVersion
		kind: self.#kind
	}
}

// Resource kinds pattern
_resourceKindsBase: {
	_base!: _

	[string]: {
		_allValuesAreValidStructs
		_setTypeMeta
		#resourceSchema: _
		#template: {
			_base
			k8s: #resourceSchema
		}
		[_]: #template
	}
}

_namespacedResourceKinds: {
	_resourceKindsBase
	_base: _namespacedResource
	[string]: [string]: namespace: string

	app: {
		#apiVersion: "argoproj.io/v1alpha1"
		#kind: "Application"
		#resourceSchema: {
			spec?: revisionHistoryLimit?: int
		}

		#template: self={
			revisionHistoryLimit: *3 | int
			k8s: spec: revisionHistoryLimit: self.revisionHistoryLimit
		}
	}
}

// Usage
argocd: _namespacedResourceKinds & {
	app: apps: {}
} @test(err, code=eval)

-- export.cue --
@experiment(aliasv2)

package main

import "encoding/yaml"

let _globalScope = self

#export: {
	#entries: [...]
	manifests: [
		for _entry in #entries
		for _ns in _entry
		for _kind, _objs in _ns
		for _name, _obj in _objs {
			_obj.k8s
		}]
	yamlStream: yaml.MarshalStream(manifests)
}

#manifests: {#export, #entries: [_globalScope]}.yamlStream

@test(err, code=eval)
-- out/errors.txt --
[eval] #manifests: error in call to encoding/yaml.MarshalStream: <- invalid {namespace:string,revisionHistoryLimit:*3 | int,k8s:_|_(#entries.0.argocd.app.apps: <- invalid value at path '#entries.0.argocd.app.apps'),name:string}:
    ./export.cue:18:14
    ./in.cue:15:38
    ./in.cue:16:8
    ./in.cue:23:3
    ./in.cue:40:8
    ./in.cue:47:22
    ./in.cue:65:13
[incomplete] _setTypeMeta.#template.k8s.apiVersion: required field missing: #apiVersion:
    ./in.cue:23:20
[incomplete] _setTypeMeta.#template.k8s.kind: required field missing: #kind:
    ./in.cue:24:14
[eval] _namespacedResourceKinds.app.#template.k8s.apiVersion: field not allowed:
    ./in.cue:23:3
[eval] _namespacedResourceKinds.app.#template.k8s.kind: field not allowed:
    ./in.cue:24:3
[eval] _namespacedResourceKinds.app.#template.k8s.metadata: field not allowed:
    ./in.cue:5:7
    ./in.cue:11:7
[eval] argocd.app.apps: 4 errors in empty disjunction:
argocd.app.apps.k8s.apiVersion: field not allowed:
    ./in.cue:23:3
argocd.app.apps.k8s.kind: field not allowed:
    ./in.cue:24:3
argocd.app.apps.k8s.metadata: field not allowed:
    ./in.cue:5:7
    ./in.cue:11:7
argocd.app.apps: <- invalid {namespace:string,revisionHistoryLimit:*3 | int,k8s:_|_(argocd.app.apps.k8s.apiVersion: field not allowed (and 2 more errors)),name:string}:
    ./in.cue:16:8
    ./in.cue:15:38
    ./in.cue:40:8
    ./in.cue:47:22
    ./in.cue:65:13
[eval] argocd.app.#template.k8s.apiVersion: field not allowed:
    ./in.cue:23:3
[eval] argocd.app.#template.k8s.kind: field not allowed:
    ./in.cue:24:3
[eval] argocd.app.#template.k8s.metadata: field not allowed:
    ./in.cue:5:7
    ./in.cue:11:7
-- out/eval/stats --
Leaks:  1
Freed:  187
Reused: 127
Allocs: 61
Retain: 0

Unifications: 100
Conjuncts:    289
Disjuncts:    28

NumCloseIDs: 77

ConjunctInfos:       196
MaxConjunctInfos:    8
MaxReqSets:          9
-- out/evalalpha --
Errors:
_namespacedResourceKinds.app.#template.k8s.apiVersion: field not allowed:
    ./in.cue:23:3
_namespacedResourceKinds.app.#template.k8s.kind: field not allowed:
    ./in.cue:24:3
_namespacedResourceKinds.app.#template.k8s.metadata: field not allowed:
    ./in.cue:5:7
    ./in.cue:11:7
argocd.app.#template.k8s.apiVersion: field not allowed:
    ./in.cue:23:3
argocd.app.#template.k8s.kind: field not allowed:
    ./in.cue:24:3
argocd.app.#template.k8s.metadata: field not allowed:
    ./in.cue:5:7
    ./in.cue:11:7
argocd.app.apps: 4 errors in empty disjunction:
argocd.app.apps.k8s.apiVersion: field not allowed:
    ./in.cue:23:3
argocd.app.apps.k8s.kind: field not allowed:
    ./in.cue:24:3
argocd.app.apps.k8s.metadata: field not allowed:
    ./in.cue:5:7
    ./in.cue:11:7
#manifests: error in call to encoding/yaml.MarshalStream: <- invalid {namespace:string,revisionHistoryLimit:*3 | int,k8s:_|_(#entries.0.argocd.app.apps: <- invalid value at path '#entries.0.argocd.app.apps'),name:string}:
    ./export.cue:18:14
    ./in.cue:15:38
    ./in.cue:16:8
    ./in.cue:23:3
    ./in.cue:40:8
    ./in.cue:47:22
    ./in.cue:65:13
argocd.app.apps: <- invalid {namespace:string,revisionHistoryLimit:*3 | int,k8s:_|_(argocd.app.apps.k8s.apiVersion: field not allowed (and 2 more errors)),name:string}:
    ./in.cue:16:8
    ./in.cue:15:38
    ./in.cue:40:8
    ./in.cue:47:22
    ./in.cue:65:13

Result:
(_|_){
  // [eval]
  let _globalScope#1 = (_|_){
    // [structural_cycle] _globalScope: structural cycle
  }
  #export: (#struct){
    #entries: (list){
    }
    manifests: (#list){
    }
    yamlStream: (string){ "" }
  }
  #manifests: (_|_){
    // [eval] #manifests: error in call to encoding/yaml.MarshalStream: <- invalid {namespace:string,revisionHistoryLimit:*3 | int,k8s:_|_(#entries.0.argocd.app.apps: <- invalid value at path '#entries.0.argocd.app.apps'),name:string}:
    //     ./export.cue:18:14
    //     ./in.cue:15:38
    //     ./in.cue:16:8
    //     ./in.cue:23:3
    //     ./in.cue:40:8
    //     ./in.cue:47:22
    //     ./in.cue:65:13
  }
  _objectBase(:main): (struct){
    name: (string){ string }
    k8s: (struct){
      metadata: (struct){
        name: (string){ string }
      }
    }
  }
  _namespacedResource(:main): (struct){
    namespace: (string){ string }
    k8s: (struct){
      metadata: (struct){
        namespace: (string){ string }
        name: (string){ string }
      }
    }
    name: (string){ string }
  }
  _allValuesAreValidStructs(:main): (struct){
  }
  _setTypeMeta(:main): (struct){
    #apiVersion!: (string){ string }
    #kind!: (string){ string }
    #template: (#struct){
      k8s: (#struct){
        apiVersion: (_|_){
          // [incomplete] _setTypeMeta.#template.k8s.apiVersion: required field missing: #apiVersion:
          //     ./in.cue:23:20
        }
        kind: (_|_){
          // [incomplete] _setTypeMeta.#template.k8s.kind: required field missing: #kind:
          //     ./in.cue:24:14
        }
      }
    }
  }
  _resourceKindsBase(:main): (struct){
    _base(:main)!: (_){ _ }
  }
  _namespacedResourceKinds(:main): (_|_){
    // [eval]
    _base(:main): ~(_namespacedResource(:main))
    app: (_|_){
      // [eval]
      #apiVersion: (string){ "argoproj.io/v1alpha1" }
      #kind: (string){ "Application" }
      #resourceSchema: (#struct){
        spec?: (#struct){
          revisionHistoryLimit?: (int){ int }
        }
      }
      #template: (_|_){
        // [eval]
        revisionHistoryLimit: (int){ |(*(int){ 3 }, (int){ int }) }
        k8s: (_|_){
          // [eval]
          spec: (#struct){
            revisionHistoryLimit: (int){ |(*(int){ 3 }, (int){ int }) }
          }
          apiVersion: (_|_){
            // [eval] _namespacedResourceKinds.app.#template.k8s.apiVersion: field not allowed:
            //     ./in.cue:23:3
          }
          kind: (_|_){
            // [eval] _namespacedResourceKinds.app.#template.k8s.kind: field not allowed:
            //     ./in.cue:24:3
          }
          metadata: (_|_){
            // [eval] _namespacedResourceKinds.app.#template.k8s.metadata: field not allowed:
            //     ./in.cue:5:7
            //     ./in.cue:11:7
            namespace: (_|_){
              // [eval] _namespacedResourceKinds.app.#template.k8s.metadata.namespace: field not allowed:
              //     ./in.cue:11:17
            }
            name: (_|_){
              // [eval] _namespacedResourceKinds.app.#template.k8s.metadata.name: field not allowed:
              //     ./in.cue:5:17
            }
          }
        }
        namespace: (string){ string }
        name: (string){ string }
      }
    }
  }
  argocd: (_|_){
    // [eval]
    app: (_|_){
      // [eval]
      apps: (_|_){
        // [eval] argocd.app.apps: 4 errors in empty disjunction:
        // argocd.app.apps.k8s.apiVersion: field not allowed:
        //     ./in.cue:23:3
        // argocd.app.apps.k8s.kind: field not allowed:
        //     ./in.cue:24:3
        // argocd.app.apps.k8s.metadata: field not allowed:
        //     ./in.cue:5:7
        //     ./in.cue:11:7
        // argocd.app.apps: <- invalid {namespace:string,revisionHistoryLimit:*3 | int,k8s:_|_(argocd.app.apps.k8s.apiVersion: field not allowed (and 2 more errors)),name:string}:
        //     ./in.cue:16:8
        //     ./in.cue:15:38
        //     ./in.cue:40:8
        //     ./in.cue:47:22
        //     ./in.cue:65:13
        namespace: (string){ string }
        revisionHistoryLimit: (_){ _ }
        k8s: (#struct){
          spec: (#struct){
            revisionHistoryLimit: (_){ _ }
          }
          apiVersion: (_){ _ }
          kind: (_){ _ }
          metadata: (#struct){
            namespace: (_){ _ }
            name: (_){ _ }
          }
        }
        name: (string){ string }
      }
      #apiVersion: (string){ "argoproj.io/v1alpha1" }
      #kind: (string){ "Application" }
      #resourceSchema: (#struct){
        spec?: (#struct){
          revisionHistoryLimit?: (int){ int }
        }
      }
      #template: (_|_){
        // [eval]
        revisionHistoryLimit: (int){ |(*(int){ 3 }, (int){ int }) }
        k8s: (_|_){
          // [eval]
          spec: (#struct){
            revisionHistoryLimit: (int){ |(*(int){ 3 }, (int){ int }) }
          }
          apiVersion: (_|_){
            // [eval] argocd.app.#template.k8s.apiVersion: field not allowed:
            //     ./in.cue:23:3
          }
          kind: (_|_){
            // [eval] argocd.app.#template.k8s.kind: field not allowed:
            //     ./in.cue:24:3
          }
          metadata: (_|_){
            // [eval] argocd.app.#template.k8s.metadata: field not allowed:
            //     ./in.cue:5:7
            //     ./in.cue:11:7
            namespace: (_|_){
              // [eval] argocd.app.#template.k8s.metadata.namespace: field not allowed:
              //     ./in.cue:11:17
            }
            name: (_|_){
              // [eval] argocd.app.#template.k8s.metadata.name: field not allowed:
              //     ./in.cue:5:17
            }
          }
        }
        namespace: (string){ string }
        name: (string){ string }
      }
    }
    _base(:main): ~(_namespacedResource(:main))
  }
}
-- out/eval --
