// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package hcl2shim

import (
	"fmt"
	"strconv"
	"strings"

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

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

// FlatmapValueFromHCL2 converts a value from HCL2 (really, from the cty dynamic
// types library that HCL2 uses) to a map compatible with what would be
// produced by the "flatmap" package.
//
// The type of the given value informs the structure of the resulting map.
// The value must be of an object type or this function will panic.
//
// Flatmap values can only represent maps when they are of primitive types,
// so the given value must not have any maps of complex types or the result
// is undefined.
func FlatmapValueFromHCL2(v cty.Value) map[string]string {
	if v.IsNull() {
		return nil
	}

	if !v.Type().IsObjectType() {
		panic(fmt.Sprintf("HCL2ValueFromFlatmap called on %#v", v.Type()))
	}

	m := make(map[string]string)
	flatmapValueFromHCL2Map(m, "", v)
	return m
}

func flatmapValueFromHCL2Value(m map[string]string, key string, val cty.Value) {
	ty := val.Type()
	switch {
	case ty.IsPrimitiveType() || ty == cty.DynamicPseudoType:
		flatmapValueFromHCL2Primitive(m, key, val)
	case ty.IsObjectType() || ty.IsMapType():
		flatmapValueFromHCL2Map(m, key+".", val)
	case ty.IsTupleType() || ty.IsListType() || ty.IsSetType():
		flatmapValueFromHCL2Seq(m, key+".", val)
	default:
		panic(fmt.Sprintf("cannot encode %s to flatmap", ty.FriendlyName()))
	}
}

func flatmapValueFromHCL2Primitive(m map[string]string, key string, val cty.Value) {
	if !val.IsKnown() {
		m[key] = UnknownVariableValue
		return
	}
	if val.IsNull() {
		// Omit entirely
		return
	}

	var err error
	val, err = convert.Convert(val, cty.String)
	if err != nil {
		// Should not be possible, since all primitive types can convert to string.
		panic(fmt.Sprintf("invalid primitive encoding to flatmap: %s", err))
	}
	m[key] = val.AsString()
}

func flatmapValueFromHCL2Map(m map[string]string, prefix string, val cty.Value) {
	if val.IsNull() {
		// Omit entirely
		return
	}
	if !val.IsKnown() {
		switch {
		case val.Type().IsObjectType():
			// Whole objects can't be unknown in flatmap, so instead we'll
			// just write all of the attribute values out as unknown.
			for name, aty := range val.Type().AttributeTypes() {
				flatmapValueFromHCL2Value(m, prefix+name, cty.UnknownVal(aty))
			}
		default:
			m[prefix+"%"] = UnknownVariableValue
		}
		return
	}

	len := 0
	for it := val.ElementIterator(); it.Next(); {
		ak, av := it.Element()
		name := ak.AsString()
		flatmapValueFromHCL2Value(m, prefix+name, av)
		len++
	}
	if !val.Type().IsObjectType() { // objects don't have an explicit count included, since their attribute count is fixed
		m[prefix+"%"] = strconv.Itoa(len)
	}
}

func flatmapValueFromHCL2Seq(m map[string]string, prefix string, val cty.Value) {
	if val.IsNull() {
		// Omit entirely
		return
	}
	if !val.IsKnown() {
		m[prefix+"#"] = UnknownVariableValue
		return
	}

	// For sets this won't actually generate exactly what helper/schema would've
	// generated, because we don't have access to the set key function it
	// would've used. However, in practice it doesn't actually matter what the
	// keys are as long as they are unique, so we'll just generate sequential
	// indexes for them as if it were a list.
	//
	// An important implication of this, however, is that the set ordering will
	// not be consistent across mutations and so different keys may be assigned
	// to the same value when round-tripping. Since this shim is intended to
	// be short-lived and not used for round-tripping, we accept this.
	i := 0
	for it := val.ElementIterator(); it.Next(); {
		_, av := it.Element()
		key := prefix + strconv.Itoa(i)
		flatmapValueFromHCL2Value(m, key, av)
		i++
	}
	m[prefix+"#"] = strconv.Itoa(i)
}

// HCL2ValueFromFlatmap converts a map compatible with what would be produced
// by the "flatmap" package to a HCL2 (really, the cty dynamic types library
// that HCL2 uses) object type.
//
// The intended result type must be provided in order to guide how the
// map contents are decoded. This must be an object type or this function
// will panic.
//
// Flatmap values can only represent maps when they are of primitive types,
// so the given type must not have any maps of complex types or the result
// is undefined.
//
// The result may contain null values if the given map does not contain keys
// for all of the different key paths implied by the given type.
func HCL2ValueFromFlatmap(m map[string]string, ty cty.Type) (cty.Value, error) {
	if m == nil {
		return cty.NullVal(ty), nil
	}
	if !ty.IsObjectType() {
		panic(fmt.Sprintf("HCL2ValueFromFlatmap called on %#v", ty))
	}

	return hcl2ValueFromFlatmapObject(m, "", ty.AttributeTypes())
}

func hcl2ValueFromFlatmapValue(m map[string]string, key string, ty cty.Type) (cty.Value, error) {
	var val cty.Value
	var err error
	switch {
	case ty.IsPrimitiveType():
		val, err = hcl2ValueFromFlatmapPrimitive(m, key, ty)
	case ty.IsObjectType():
		val, err = hcl2ValueFromFlatmapObject(m, key+".", ty.AttributeTypes())
	case ty.IsTupleType():
		val, err = hcl2ValueFromFlatmapTuple(m, key+".", ty.TupleElementTypes())
	case ty.IsMapType():
		val, err = hcl2ValueFromFlatmapMap(m, key+".", ty)
	case ty.IsListType():
		val, err = hcl2ValueFromFlatmapList(m, key+".", ty)
	case ty.IsSetType():
		val, err = hcl2ValueFromFlatmapSet(m, key+".", ty)
	default:
		err = fmt.Errorf("cannot decode %s from flatmap", ty.FriendlyName())
	}

	if err != nil {
		return cty.DynamicVal, err
	}
	return val, nil
}

func hcl2ValueFromFlatmapPrimitive(m map[string]string, key string, ty cty.Type) (cty.Value, error) {
	rawVal, exists := m[key]
	if !exists {
		return cty.NullVal(ty), nil
	}
	if rawVal == UnknownVariableValue {
		return cty.UnknownVal(ty), nil
	}

	var err error
	val := cty.StringVal(rawVal)
	val, err = convert.Convert(val, ty)
	if err != nil {
		// This should never happen for _valid_ input, but flatmap data might
		// be tampered with by the user and become invalid.
		return cty.DynamicVal, fmt.Errorf("invalid value for %q in state: %s", key, err)
	}

	return val, nil
}

func hcl2ValueFromFlatmapObject(m map[string]string, prefix string, atys map[string]cty.Type) (cty.Value, error) {
	vals := make(map[string]cty.Value)
	for name, aty := range atys {
		val, err := hcl2ValueFromFlatmapValue(m, prefix+name, aty)
		if err != nil {
			return cty.DynamicVal, err
		}
		vals[name] = val
	}
	return cty.ObjectVal(vals), nil
}

func hcl2ValueFromFlatmapTuple(m map[string]string, prefix string, etys []cty.Type) (cty.Value, error) {
	var vals []cty.Value

	// if the container is unknown, there is no count string
	listName := strings.TrimRight(prefix, ".")
	if m[listName] == UnknownVariableValue {
		return cty.UnknownVal(cty.Tuple(etys)), nil
	}

	countStr, exists := m[prefix+"#"]
	if !exists {
		return cty.NullVal(cty.Tuple(etys)), nil
	}
	if countStr == UnknownVariableValue {
		return cty.UnknownVal(cty.Tuple(etys)), nil
	}

	count, err := strconv.Atoi(countStr)
	if err != nil {
		return cty.DynamicVal, fmt.Errorf("invalid count value for %q in state: %s", prefix, err)
	}
	if count != len(etys) {
		return cty.DynamicVal, fmt.Errorf("wrong number of values for %q in state: got %d, but need %d", prefix, count, len(etys))
	}

	vals = make([]cty.Value, len(etys))
	for i, ety := range etys {
		key := prefix + strconv.Itoa(i)
		val, err := hcl2ValueFromFlatmapValue(m, key, ety)
		if err != nil {
			return cty.DynamicVal, err
		}
		vals[i] = val
	}
	return cty.TupleVal(vals), nil
}

func hcl2ValueFromFlatmapMap(m map[string]string, prefix string, ty cty.Type) (cty.Value, error) {
	vals := make(map[string]cty.Value)
	ety := ty.ElementType()

	// if the container is unknown, there is no count string
	listName := strings.TrimRight(prefix, ".")
	if m[listName] == UnknownVariableValue {
		return cty.UnknownVal(ty), nil
	}

	// We actually don't really care about the "count" of a map for our
	// purposes here, but we do need to check if it _exists_ in order to
	// recognize the difference between null (not set at all) and empty.
	if strCount, exists := m[prefix+"%"]; !exists {
		return cty.NullVal(ty), nil
	} else if strCount == UnknownVariableValue {
		return cty.UnknownVal(ty), nil
	}

	for fullKey := range m {
		if !strings.HasPrefix(fullKey, prefix) {
			continue
		}

		// The flatmap format doesn't allow us to distinguish between keys
		// that contain periods and nested objects, so by convention a
		// map is only ever of primitive type in flatmap, and we just assume
		// that the remainder of the raw key (dots and all) is the key we
		// want in the result value.
		key := fullKey[len(prefix):]
		if key == "%" {
			// Ignore the "count" key
			continue
		}

		val, err := hcl2ValueFromFlatmapValue(m, fullKey, ety)
		if err != nil {
			return cty.DynamicVal, err
		}
		vals[key] = val
	}

	if len(vals) == 0 {
		return cty.MapValEmpty(ety), nil
	}
	return cty.MapVal(vals), nil
}

func hcl2ValueFromFlatmapList(m map[string]string, prefix string, ty cty.Type) (cty.Value, error) {
	var vals []cty.Value

	// if the container is unknown, there is no count string
	listName := strings.TrimRight(prefix, ".")
	if m[listName] == UnknownVariableValue {
		return cty.UnknownVal(ty), nil
	}

	countStr, exists := m[prefix+"#"]
	if !exists {
		return cty.NullVal(ty), nil
	}
	if countStr == UnknownVariableValue {
		return cty.UnknownVal(ty), nil
	}

	count, err := strconv.Atoi(countStr)
	if err != nil {
		return cty.DynamicVal, fmt.Errorf("invalid count value for %q in state: %s", prefix, err)
	}

	ety := ty.ElementType()
	if count == 0 {
		return cty.ListValEmpty(ety), nil
	}

	vals = make([]cty.Value, count)
	for i := 0; i < count; i++ {
		key := prefix + strconv.Itoa(i)
		val, err := hcl2ValueFromFlatmapValue(m, key, ety)
		if err != nil {
			return cty.DynamicVal, err
		}
		vals[i] = val
	}

	return cty.ListVal(vals), nil
}

func hcl2ValueFromFlatmapSet(m map[string]string, prefix string, ty cty.Type) (cty.Value, error) {
	var vals []cty.Value
	ety := ty.ElementType()

	// if the container is unknown, there is no count string
	listName := strings.TrimRight(prefix, ".")
	if m[listName] == UnknownVariableValue {
		return cty.UnknownVal(ty), nil
	}

	strCount, exists := m[prefix+"#"]
	if !exists {
		return cty.NullVal(ty), nil
	} else if strCount == UnknownVariableValue {
		return cty.UnknownVal(ty), nil
	}

	// Keep track of keys we've seen, se we don't add the same set value
	// multiple times. The cty.Set will normally de-duplicate values, but we may
	// have unknown values that would not show as equivalent.
	seen := map[string]bool{}

	for fullKey := range m {
		if !strings.HasPrefix(fullKey, prefix) {
			continue
		}
		subKey := fullKey[len(prefix):]
		if subKey == "#" {
			// Ignore the "count" key
			continue
		}
		key := fullKey
		if dot := strings.IndexByte(subKey, '.'); dot != -1 {
			key = fullKey[:dot+len(prefix)]
		}

		if seen[key] {
			continue
		}

		seen[key] = true

		// The flatmap format doesn't allow us to distinguish between keys
		// that contain periods and nested objects, so by convention a
		// map is only ever of primitive type in flatmap, and we just assume
		// that the remainder of the raw key (dots and all) is the key we
		// want in the result value.

		val, err := hcl2ValueFromFlatmapValue(m, key, ety)
		if err != nil {
			return cty.DynamicVal, err
		}
		vals = append(vals, val)
	}

	if len(vals) == 0 && strCount == "1" {
		// An empty set wouldn't be represented in the flatmap, so this must be
		// a single empty object since the count is actually 1.
		// Add an appropriately typed null value to the set.
		var val cty.Value
		switch {
		case ety.IsMapType():
			val = cty.MapValEmpty(ety)
		case ety.IsListType():
			val = cty.ListValEmpty(ety)
		case ety.IsSetType():
			val = cty.SetValEmpty(ety)
		case ety.IsObjectType():
			// TODO: cty.ObjectValEmpty
			objectMap := map[string]cty.Value{}
			for attr, ty := range ety.AttributeTypes() {
				objectMap[attr] = cty.NullVal(ty)
			}
			val = cty.ObjectVal(objectMap)
		default:
			val = cty.NullVal(ety)
		}
		vals = append(vals, val)

	} else if len(vals) == 0 {
		return cty.SetValEmpty(ety), nil
	}

	return cty.SetVal(vals), nil
}
