package objchange

import (
	"fmt"

	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/terraform/internal/configs/configschema"
)

// ProposedNew constructs a proposed new object value by combining the
// computed attribute values from "prior" with the configured attribute values
// from "config".
//
// Both value must conform to the given schema's implied type, or this function
// will panic.
//
// The prior value must be wholly known, but the config value may be unknown
// or have nested unknown values.
//
// The merging of the two objects includes the attributes of any nested blocks,
// which will be correlated in a manner appropriate for their nesting mode.
// Note in particular that the correlation for blocks backed by sets is a
// heuristic based on matching non-computed attribute values and so it may
// produce strange results with more "extreme" cases, such as a nested set
// block where _all_ attributes are computed.
func ProposedNew(schema *configschema.Block, prior, config cty.Value) cty.Value {
	// If the config and prior are both null, return early here before
	// populating the prior block. The prevents non-null blocks from appearing
	// the proposed state value.
	if config.IsNull() && prior.IsNull() {
		return prior
	}

	if prior.IsNull() {
		// In this case, we will construct a synthetic prior value that is
		// similar to the result of decoding an empty configuration block,
		// which simplifies our handling of the top-level attributes/blocks
		// below by giving us one non-null level of object to pull values from.
		//
		// "All attributes null" happens to be the definition of EmptyValue for
		// a Block, so we can just delegate to that
		prior = schema.EmptyValue()
	}
	return proposedNew(schema, prior, config)
}

// PlannedDataResourceObject is similar to proposedNewBlock but tailored for
// planning data resources in particular. Specifically, it replaces the values
// of any Computed attributes not set in the configuration with an unknown
// value, which serves as a placeholder for a value to be filled in by the
// provider when the data resource is finally read.
//
// Data resources are different because the planning of them is handled
// entirely within Terraform Core and not subject to customization by the
// provider. This function is, in effect, producing an equivalent result to
// passing the proposedNewBlock result into a provider's PlanResourceChange
// function, assuming a fixed implementation of PlanResourceChange that just
// fills in unknown values as needed.
func PlannedDataResourceObject(schema *configschema.Block, config cty.Value) cty.Value {
	// Our trick here is to run the proposedNewBlock logic with an
	// entirely-unknown prior value. Because of cty's unknown short-circuit
	// behavior, any operation on prior returns another unknown, and so
	// unknown values propagate into all of the parts of the resulting value
	// that would normally be filled in by preserving the prior state.
	prior := cty.UnknownVal(schema.ImpliedType())
	return proposedNew(schema, prior, config)
}

func proposedNew(schema *configschema.Block, prior, config cty.Value) cty.Value {
	if config.IsNull() || !config.IsKnown() {
		// A block config should never be null at this point. The only nullable
		// block type is NestingSingle, which will return early before coming
		// back here. We'll allow the null here anyway to free callers from
		// needing to specifically check for these cases, and any mismatch will
		// be caught in validation, so just take the prior value rather than
		// the invalid null.
		return prior
	}

	if (!prior.Type().IsObjectType()) || (!config.Type().IsObjectType()) {
		panic("ProposedNew only supports object-typed values")
	}

	// From this point onwards, we can assume that both values are non-null
	// object types, and that the config value itself is known (though it
	// may contain nested values that are unknown.)
	newAttrs := proposedNewAttributes(schema.Attributes, prior, config)

	// Merging nested blocks is a little more complex, since we need to
	// correlate blocks between both objects and then recursively propose
	// a new object for each. The correlation logic depends on the nesting
	// mode for each block type.
	for name, blockType := range schema.BlockTypes {
		priorV := prior.GetAttr(name)
		configV := config.GetAttr(name)
		newAttrs[name] = proposedNewNestedBlock(blockType, priorV, configV)
	}

	return cty.ObjectVal(newAttrs)
}

func proposedNewNestedBlock(schema *configschema.NestedBlock, prior, config cty.Value) cty.Value {
	// The only time we should encounter an entirely unknown block is from the
	// use of dynamic with an unknown for_each expression.
	if !config.IsKnown() {
		return config
	}

	var newV cty.Value

	switch schema.Nesting {

	case configschema.NestingSingle:
		// A NestingSingle configuration block value can be null, and since it
		// cannot be computed we can always take the configuration value.
		if config.IsNull() {
			newV = config
			break
		}

		// Otherwise use the same assignment rules as NestingGroup
		fallthrough
	case configschema.NestingGroup:
		newV = ProposedNew(&schema.Block, prior, config)

	case configschema.NestingList:
		// Nested blocks are correlated by index.
		configVLen := 0
		if !config.IsNull() {
			configVLen = config.LengthInt()
		}
		if configVLen > 0 {
			newVals := make([]cty.Value, 0, configVLen)
			for it := config.ElementIterator(); it.Next(); {
				idx, configEV := it.Element()
				if prior.IsKnown() && (prior.IsNull() || !prior.HasIndex(idx).True()) {
					// If there is no corresponding prior element then
					// we just take the config value as-is.
					newVals = append(newVals, configEV)
					continue
				}
				priorEV := prior.Index(idx)

				newEV := ProposedNew(&schema.Block, priorEV, configEV)
				newVals = append(newVals, newEV)
			}
			// Despite the name, a NestingList might also be a tuple, if
			// its nested schema contains dynamically-typed attributes.
			if config.Type().IsTupleType() {
				newV = cty.TupleVal(newVals)
			} else {
				newV = cty.ListVal(newVals)
			}
		} else {
			// Despite the name, a NestingList might also be a tuple, if
			// its nested schema contains dynamically-typed attributes.
			if config.Type().IsTupleType() {
				newV = cty.EmptyTupleVal
			} else {
				newV = cty.ListValEmpty(schema.ImpliedType())
			}
		}

	case configschema.NestingMap:
		// Despite the name, a NestingMap may produce either a map or
		// object value, depending on whether the nested schema contains
		// dynamically-typed attributes.
		if config.Type().IsObjectType() {
			// Nested blocks are correlated by key.
			configVLen := 0
			if config.IsKnown() && !config.IsNull() {
				configVLen = config.LengthInt()
			}
			if configVLen > 0 {
				newVals := make(map[string]cty.Value, configVLen)
				atys := config.Type().AttributeTypes()
				for name := range atys {
					configEV := config.GetAttr(name)
					if !prior.IsKnown() || prior.IsNull() || !prior.Type().HasAttribute(name) {
						// If there is no corresponding prior element then
						// we just take the config value as-is.
						newVals[name] = configEV
						continue
					}
					priorEV := prior.GetAttr(name)

					newEV := ProposedNew(&schema.Block, priorEV, configEV)
					newVals[name] = newEV
				}
				// Although we call the nesting mode "map", we actually use
				// object values so that elements might have different types
				// in case of dynamically-typed attributes.
				newV = cty.ObjectVal(newVals)
			} else {
				newV = cty.EmptyObjectVal
			}
		} else {
			configVLen := 0
			if config.IsKnown() && !config.IsNull() {
				configVLen = config.LengthInt()
			}
			if configVLen > 0 {
				newVals := make(map[string]cty.Value, configVLen)
				for it := config.ElementIterator(); it.Next(); {
					idx, configEV := it.Element()
					k := idx.AsString()
					if prior.IsKnown() && (prior.IsNull() || !prior.HasIndex(idx).True()) {
						// If there is no corresponding prior element then
						// we just take the config value as-is.
						newVals[k] = configEV
						continue
					}
					priorEV := prior.Index(idx)

					newEV := ProposedNew(&schema.Block, priorEV, configEV)
					newVals[k] = newEV
				}
				newV = cty.MapVal(newVals)
			} else {
				newV = cty.MapValEmpty(schema.ImpliedType())
			}
		}

	case configschema.NestingSet:
		if !config.Type().IsSetType() {
			panic("configschema.NestingSet value is not a set as expected")
		}

		// Nested blocks are correlated by comparing the element values
		// after eliminating all of the computed attributes. In practice,
		// this means that any config change produces an entirely new
		// nested object, and we only propagate prior computed values
		// if the non-computed attribute values are identical.
		var cmpVals [][2]cty.Value
		if prior.IsKnown() && !prior.IsNull() {
			cmpVals = setElementCompareValues(&schema.Block, prior, false)
		}
		configVLen := 0
		if config.IsKnown() && !config.IsNull() {
			configVLen = config.LengthInt()
		}
		if configVLen > 0 {
			used := make([]bool, len(cmpVals)) // track used elements in case multiple have the same compare value
			newVals := make([]cty.Value, 0, configVLen)
			for it := config.ElementIterator(); it.Next(); {
				_, configEV := it.Element()
				var priorEV cty.Value
				for i, cmp := range cmpVals {
					if used[i] {
						continue
					}
					if cmp[1].RawEquals(configEV) {
						priorEV = cmp[0]
						used[i] = true // we can't use this value on a future iteration
						break
					}
				}
				if priorEV == cty.NilVal {
					priorEV = cty.NullVal(schema.ImpliedType())
				}

				newEV := ProposedNew(&schema.Block, priorEV, configEV)
				newVals = append(newVals, newEV)
			}
			newV = cty.SetVal(newVals)
		} else {
			newV = cty.SetValEmpty(schema.Block.ImpliedType())
		}

	default:
		// Should never happen, since the above cases are comprehensive.
		panic(fmt.Sprintf("unsupported block nesting mode %s", schema.Nesting))
	}
	return newV
}

func proposedNewAttributes(attrs map[string]*configschema.Attribute, prior, config cty.Value) map[string]cty.Value {
	newAttrs := make(map[string]cty.Value, len(attrs))
	for name, attr := range attrs {
		var priorV cty.Value
		if prior.IsNull() {
			priorV = cty.NullVal(prior.Type().AttributeType(name))
		} else {
			priorV = prior.GetAttr(name)
		}

		configV := config.GetAttr(name)
		var newV cty.Value
		switch {
		case attr.Computed && attr.Optional:
			// This is the trickiest scenario: we want to keep the prior value
			// if the config isn't overriding it. Note that due to some
			// ambiguity here, setting an optional+computed attribute from
			// config and then later switching the config to null in a
			// subsequent change causes the initial config value to be "sticky"
			// unless the provider specifically overrides it during its own
			// plan customization step.
			if configV.IsNull() {
				newV = priorV
			} else {
				newV = configV
			}
		case attr.Computed:
			// configV will always be null in this case, by definition.
			// priorV may also be null, but that's okay.
			newV = priorV
		default:
			if attr.NestedType != nil {
				// For non-computed NestedType attributes, we need to descend
				// into the individual nested attributes to build the final
				// value, unless the entire nested attribute is unknown.
				if !configV.IsKnown() {
					newV = configV
				} else {
					newV = proposedNewNestedType(attr.NestedType, priorV, configV)
				}
			} else {
				// For non-computed attributes, we always take the config value,
				// even if it is null. If it's _required_ then null values
				// should've been caught during an earlier validation step, and
				// so we don't really care about that here.
				newV = configV
			}
		}
		newAttrs[name] = newV
	}
	return newAttrs
}

func proposedNewNestedType(schema *configschema.Object, prior, config cty.Value) cty.Value {
	// If the config is null or empty, we will be using this default value.
	newV := config

	switch schema.Nesting {
	case configschema.NestingSingle:
		if !config.IsNull() {
			newV = cty.ObjectVal(proposedNewAttributes(schema.Attributes, prior, config))
		} else {
			newV = cty.NullVal(config.Type())
		}

	case configschema.NestingList:
		// Nested blocks are correlated by index.
		configVLen := 0
		if config.IsKnown() && !config.IsNull() {
			configVLen = config.LengthInt()
		}

		if configVLen > 0 {
			newVals := make([]cty.Value, 0, configVLen)
			for it := config.ElementIterator(); it.Next(); {
				idx, configEV := it.Element()
				if prior.IsKnown() && (prior.IsNull() || !prior.HasIndex(idx).True()) {
					// If there is no corresponding prior element then
					// we just take the config value as-is.
					newVals = append(newVals, configEV)
					continue
				}
				priorEV := prior.Index(idx)

				newEV := proposedNewAttributes(schema.Attributes, priorEV, configEV)
				newVals = append(newVals, cty.ObjectVal(newEV))
			}
			// Despite the name, a NestingList might also be a tuple, if
			// its nested schema contains dynamically-typed attributes.
			if config.Type().IsTupleType() {
				newV = cty.TupleVal(newVals)
			} else {
				newV = cty.ListVal(newVals)
			}
		}

	case configschema.NestingMap:
		// Despite the name, a NestingMap may produce either a map or
		// object value, depending on whether the nested schema contains
		// dynamically-typed attributes.
		if config.Type().IsObjectType() {
			// Nested blocks are correlated by key.
			configVLen := 0
			if config.IsKnown() && !config.IsNull() {
				configVLen = config.LengthInt()
			}
			if configVLen > 0 {
				newVals := make(map[string]cty.Value, configVLen)
				atys := config.Type().AttributeTypes()
				for name := range atys {
					configEV := config.GetAttr(name)
					if !prior.IsKnown() || prior.IsNull() || !prior.Type().HasAttribute(name) {
						// If there is no corresponding prior element then
						// we just take the config value as-is.
						newVals[name] = configEV
						continue
					}
					priorEV := prior.GetAttr(name)
					newEV := proposedNewAttributes(schema.Attributes, priorEV, configEV)
					newVals[name] = cty.ObjectVal(newEV)
				}
				// Although we call the nesting mode "map", we actually use
				// object values so that elements might have different types
				// in case of dynamically-typed attributes.
				newV = cty.ObjectVal(newVals)
			}
		} else {
			configVLen := 0
			if config.IsKnown() && !config.IsNull() {
				configVLen = config.LengthInt()
			}
			if configVLen > 0 {
				newVals := make(map[string]cty.Value, configVLen)
				for it := config.ElementIterator(); it.Next(); {
					idx, configEV := it.Element()
					k := idx.AsString()
					if prior.IsKnown() && (prior.IsNull() || !prior.HasIndex(idx).True()) {
						// If there is no corresponding prior element then
						// we just take the config value as-is.
						newVals[k] = configEV
						continue
					}
					priorEV := prior.Index(idx)

					newEV := proposedNewAttributes(schema.Attributes, priorEV, configEV)
					newVals[k] = cty.ObjectVal(newEV)
				}
				newV = cty.MapVal(newVals)
			}
		}

	case configschema.NestingSet:
		// Nested blocks are correlated by comparing the element values
		// after eliminating all of the computed attributes. In practice,
		// this means that any config change produces an entirely new
		// nested object, and we only propagate prior computed values
		// if the non-computed attribute values are identical.
		var cmpVals [][2]cty.Value
		if prior.IsKnown() && !prior.IsNull() {
			cmpVals = setElementCompareValuesFromObject(schema, prior)
		}
		configVLen := 0
		if config.IsKnown() && !config.IsNull() {
			configVLen = config.LengthInt()
		}
		if configVLen > 0 {
			used := make([]bool, len(cmpVals)) // track used elements in case multiple have the same compare value
			newVals := make([]cty.Value, 0, configVLen)
			for it := config.ElementIterator(); it.Next(); {
				_, configEV := it.Element()
				var priorEV cty.Value
				for i, cmp := range cmpVals {
					if used[i] {
						continue
					}
					if cmp[1].RawEquals(configEV) {
						priorEV = cmp[0]
						used[i] = true // we can't use this value on a future iteration
						break
					}
				}
				if priorEV == cty.NilVal {
					newVals = append(newVals, configEV)
				} else {
					newEV := proposedNewAttributes(schema.Attributes, priorEV, configEV)
					newVals = append(newVals, cty.ObjectVal(newEV))
				}
			}
			newV = cty.SetVal(newVals)
		}
	}

	return newV
}

// setElementCompareValues takes a known, non-null value of a cty.Set type and
// returns a table -- constructed of two-element arrays -- that maps original
// set element values to corresponding values that have all of the computed
// values removed, making them suitable for comparison with values obtained
// from configuration. The element type of the set must conform to the implied
// type of the given schema, or this function will panic.
//
// In the resulting slice, the zeroth element of each array is the original
// value and the one-indexed element is the corresponding "compare value".
//
// This is intended to help correlate prior elements with configured elements
// in proposedNewBlock. The result is a heuristic rather than an exact science,
// since e.g. two separate elements may reduce to the same value through this
// process. The caller must therefore be ready to deal with duplicates.
func setElementCompareValues(schema *configschema.Block, set cty.Value, isConfig bool) [][2]cty.Value {
	ret := make([][2]cty.Value, 0, set.LengthInt())
	for it := set.ElementIterator(); it.Next(); {
		_, ev := it.Element()
		ret = append(ret, [2]cty.Value{ev, setElementCompareValue(schema, ev, isConfig)})
	}
	return ret
}

// setElementCompareValue creates a new value that has all of the same
// non-computed attribute values as the one given but has all computed
// attribute values forced to null.
//
// If isConfig is true then non-null Optional+Computed attribute values will
// be preserved. Otherwise, they will also be set to null.
//
// The input value must conform to the schema's implied type, and the return
// value is guaranteed to conform to it.
func setElementCompareValue(schema *configschema.Block, v cty.Value, isConfig bool) cty.Value {
	if v.IsNull() || !v.IsKnown() {
		return v
	}

	attrs := map[string]cty.Value{}
	for name, attr := range schema.Attributes {
		switch {
		case attr.Computed && attr.Optional:
			if isConfig {
				attrs[name] = v.GetAttr(name)
			} else {
				attrs[name] = cty.NullVal(attr.ImpliedType())
			}
		case attr.Computed:
			attrs[name] = cty.NullVal(attr.ImpliedType())
		default:
			attrs[name] = v.GetAttr(name)
		}
	}

	for name, blockType := range schema.BlockTypes {
		elementType := blockType.Block.ImpliedType()

		switch blockType.Nesting {
		case configschema.NestingSingle, configschema.NestingGroup:
			attrs[name] = setElementCompareValue(&blockType.Block, v.GetAttr(name), isConfig)

		case configschema.NestingList, configschema.NestingSet:
			cv := v.GetAttr(name)
			if cv.IsNull() || !cv.IsKnown() {
				attrs[name] = cv
				continue
			}

			if l := cv.LengthInt(); l > 0 {
				elems := make([]cty.Value, 0, l)
				for it := cv.ElementIterator(); it.Next(); {
					_, ev := it.Element()
					elems = append(elems, setElementCompareValue(&blockType.Block, ev, isConfig))
				}

				switch {
				case blockType.Nesting == configschema.NestingSet:
					// SetValEmpty would panic if given elements that are not
					// all of the same type, but that's guaranteed not to
					// happen here because our input value was _already_ a
					// set and we've not changed the types of any elements here.
					attrs[name] = cty.SetVal(elems)

				// NestingList cases
				case elementType.HasDynamicTypes():
					attrs[name] = cty.TupleVal(elems)
				default:
					attrs[name] = cty.ListVal(elems)
				}
			} else {
				switch {
				case blockType.Nesting == configschema.NestingSet:
					attrs[name] = cty.SetValEmpty(elementType)

				// NestingList cases
				case elementType.HasDynamicTypes():
					attrs[name] = cty.EmptyTupleVal
				default:
					attrs[name] = cty.ListValEmpty(elementType)
				}
			}

		case configschema.NestingMap:
			cv := v.GetAttr(name)
			if cv.IsNull() || !cv.IsKnown() || cv.LengthInt() == 0 {
				attrs[name] = cv
				continue
			}
			elems := make(map[string]cty.Value)
			for it := cv.ElementIterator(); it.Next(); {
				kv, ev := it.Element()
				elems[kv.AsString()] = setElementCompareValue(&blockType.Block, ev, isConfig)
			}

			switch {
			case elementType.HasDynamicTypes():
				attrs[name] = cty.ObjectVal(elems)
			default:
				attrs[name] = cty.MapVal(elems)
			}

		default:
			// Should never happen, since the above cases are comprehensive.
			panic(fmt.Sprintf("unsupported block nesting mode %s", blockType.Nesting))
		}
	}

	return cty.ObjectVal(attrs)
}

// setElementCompareValues takes a known, non-null value of a cty.Set type and
// returns a table -- constructed of two-element arrays -- that maps original
// set element values to corresponding values that have all of the computed
// values removed, making them suitable for comparison with values obtained
// from configuration. The element type of the set must conform to the implied
// type of the given schema, or this function will panic.
//
// In the resulting slice, the zeroth element of each array is the original
// value and the one-indexed element is the corresponding "compare value".
//
// This is intended to help correlate prior elements with configured elements
// in proposedNewBlock. The result is a heuristic rather than an exact science,
// since e.g. two separate elements may reduce to the same value through this
// process. The caller must therefore be ready to deal with duplicates.
func setElementCompareValuesFromObject(schema *configschema.Object, set cty.Value) [][2]cty.Value {
	ret := make([][2]cty.Value, 0, set.LengthInt())
	for it := set.ElementIterator(); it.Next(); {
		_, ev := it.Element()
		ret = append(ret, [2]cty.Value{ev, setElementCompareValueFromObject(schema, ev)})
	}
	return ret
}

// setElementCompareValue creates a new value that has all of the same
// non-computed attribute values as the one given but has all computed
// attribute values forced to null.
//
// The input value must conform to the schema's implied type, and the return
// value is guaranteed to conform to it.
func setElementCompareValueFromObject(schema *configschema.Object, v cty.Value) cty.Value {
	if v.IsNull() || !v.IsKnown() {
		return v
	}
	attrs := map[string]cty.Value{}

	for name, attr := range schema.Attributes {
		attrV := v.GetAttr(name)
		switch {
		case attr.Computed:
			attrs[name] = cty.NullVal(attr.Type)
		default:
			attrs[name] = attrV
		}
	}

	return cty.ObjectVal(attrs)
}
