# 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: {}
}
-- 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
-- out/compile --
--- export.cue
{
  let _globalScope#1 = 〈1〉
  #export: {
    #entries: [
      ...,
    ]
    manifests: [
      for _, _entry in 〈1;#entries〉 for _, _ns in 〈0;_entry(:main)〉 for _kind, _objs in 〈0;_ns(:main)〉 for _name, _obj in 〈0;_objs(:main)〉 {
        〈1;_obj(:main)〉.k8s
      },
    ]
    yamlStream: 〈import;"encoding/yaml"〉.MarshalStream(〈0;manifests〉)
  }
  #manifests: {
    〈1;#export〉
    #entries: [
      〈2;let _globalScope#1〉,
    ]
  }.yamlStream
}
--- in.cue
{
  _objectBase(:main): {
    name: string
    k8s: {
      metadata: {
        name: 〈3〉.name
      }
    }
  }
  _namespacedResource(:main): {
    〈1;_objectBase(:main)〉
    namespace: string
    k8s: {
      metadata: {
        namespace: 〈3〉.namespace
      }
    }
  }
  _allValuesAreValidStructs(:main): {
    [_]: {
      (*{}|error("<- invalid \(〈1〉)"))
    }
  }
  _setTypeMeta(:main): {
    #apiVersion!: string
    #kind!: string
    #template: {
      k8s: {
        apiVersion: 〈3〉.#apiVersion
        kind: 〈3〉.#kind
      }
    }
  }
  _resourceKindsBase(:main): {
    _base(:main)!: _
    [string]: {
      〈2;_allValuesAreValidStructs(:main)〉
      〈2;_setTypeMeta(:main)〉
      #resourceSchema: _
      #template: {
        〈2;_base(:main)〉
        k8s: 〈1;#resourceSchema〉
      }
      [_]: 〈0;#template〉
    }
  }
  _namespacedResourceKinds(:main): {
    〈1;_resourceKindsBase(:main)〉
    _base(:main): 〈1;_namespacedResource(:main)〉
    [string]: {
      [string]: {
        namespace: string
      }
    }
    app: {
      #apiVersion: "argoproj.io/v1alpha1"
      #kind: "Application"
      #resourceSchema: {
        spec?: {
          revisionHistoryLimit?: int
        }
      }
      #template: {
        revisionHistoryLimit: (*3|int)
        k8s: {
          spec: {
            revisionHistoryLimit: 〈3〉.revisionHistoryLimit
          }
        }
      }
    }
  }
  argocd: (〈0;_namespacedResourceKinds(:main)〉 & {
    app: {
      apps: {}
    }
  })
}
