package configs

import (
	"github.com/hashicorp/hcl/v2"
)

// MergeBodies creates a new HCL body that contains a combination of the
// given base and override bodies. Attributes and blocks defined in the
// override body take precedence over those of the same name defined in
// the base body.
//
// If any block of a particular type appears in "override" then it will
// replace _all_ of the blocks of the same type in "base" in the new
// body.
func MergeBodies(base, override hcl.Body) hcl.Body {
	return mergeBody{
		Base:     base,
		Override: override,
	}
}

// mergeBody is a hcl.Body implementation that wraps a pair of other bodies
// and allows attributes and blocks within the override to take precedence
// over those defined in the base body.
//
// This is used to deal with dynamically-processed bodies in Module.mergeFile.
// It uses a shallow-only merging strategy where direct attributes defined
// in Override will override attributes of the same name in Base, while any
// blocks defined in Override will hide all blocks of the same type in Base.
//
// This cannot possibly "do the right thing" in all cases, because we don't
// have enough information about user intent. However, this behavior is intended
// to be reasonable for simple overriding use-cases.
type mergeBody struct {
	Base     hcl.Body
	Override hcl.Body
}

var _ hcl.Body = mergeBody{}

func (b mergeBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
	var diags hcl.Diagnostics
	baseSchema := schemaWithDynamic(schema)
	overrideSchema := schemaWithDynamic(schemaForOverrides(schema))

	baseContent, _, cDiags := b.Base.PartialContent(baseSchema)
	diags = append(diags, cDiags...)
	overrideContent, _, cDiags := b.Override.PartialContent(overrideSchema)
	diags = append(diags, cDiags...)

	content := b.prepareContent(baseContent, overrideContent)

	return content, diags
}

func (b mergeBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
	var diags hcl.Diagnostics
	baseSchema := schemaWithDynamic(schema)
	overrideSchema := schemaWithDynamic(schemaForOverrides(schema))

	baseContent, baseRemain, cDiags := b.Base.PartialContent(baseSchema)
	diags = append(diags, cDiags...)
	overrideContent, overrideRemain, cDiags := b.Override.PartialContent(overrideSchema)
	diags = append(diags, cDiags...)

	content := b.prepareContent(baseContent, overrideContent)

	remain := MergeBodies(baseRemain, overrideRemain)

	return content, remain, diags
}

func (b mergeBody) prepareContent(base *hcl.BodyContent, override *hcl.BodyContent) *hcl.BodyContent {
	content := &hcl.BodyContent{
		Attributes: make(hcl.Attributes),
	}

	// For attributes we just assign from each map in turn and let the override
	// map clobber any matching entries from base.
	for k, a := range base.Attributes {
		content.Attributes[k] = a
	}
	for k, a := range override.Attributes {
		content.Attributes[k] = a
	}

	// Things are a little more interesting for blocks because they arrive
	// as a flat list. Our merging semantics call for us to suppress blocks
	// from base if at least one block of the same type appears in override.
	// We explicitly do not try to correlate and deeply merge nested blocks,
	// since we don't have enough context here to infer user intent.

	overriddenBlockTypes := make(map[string]bool)
	for _, block := range override.Blocks {
		if block.Type == "dynamic" {
			overriddenBlockTypes[block.Labels[0]] = true
			continue
		}
		overriddenBlockTypes[block.Type] = true
	}
	for _, block := range base.Blocks {
		// We skip over dynamic blocks whose type label is an overridden type
		// but note that below we do still leave them as dynamic blocks in
		// the result because expanding the dynamic blocks that are left is
		// done much later during the core graph walks, where we can safely
		// evaluate the expressions.
		if block.Type == "dynamic" && overriddenBlockTypes[block.Labels[0]] {
			continue
		}
		if overriddenBlockTypes[block.Type] {
			continue
		}
		content.Blocks = append(content.Blocks, block)
	}
	content.Blocks = append(content.Blocks, override.Blocks...)

	return content
}

func (b mergeBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
	var diags hcl.Diagnostics
	ret := make(hcl.Attributes)

	baseAttrs, aDiags := b.Base.JustAttributes()
	diags = append(diags, aDiags...)
	overrideAttrs, aDiags := b.Override.JustAttributes()
	diags = append(diags, aDiags...)

	for k, a := range baseAttrs {
		ret[k] = a
	}
	for k, a := range overrideAttrs {
		ret[k] = a
	}

	return ret, diags
}

func (b mergeBody) MissingItemRange() hcl.Range {
	return b.Base.MissingItemRange()
}
