package configs

import (
	"fmt"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/hclsyntax"
	"github.com/zclconf/go-cty/cty"
)

// SynthBody produces a synthetic hcl.Body that behaves as if it had attributes
// corresponding to the elements given in the values map.
//
// This is useful in situations where, for example, values provided on the
// command line can override values given in configuration, using MergeBodies.
//
// The given filename is used in case any diagnostics are returned. Since
// the created body is synthetic, it is likely that this will not be a "real"
// filename. For example, if from a command line argument it could be
// a representation of that argument's name, such as "-var=...".
func SynthBody(filename string, values map[string]cty.Value) hcl.Body {
	return synthBody{
		Filename: filename,
		Values:   values,
	}
}

type synthBody struct {
	Filename string
	Values   map[string]cty.Value
}

func (b synthBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
	content, remain, diags := b.PartialContent(schema)
	remainS := remain.(synthBody)
	for name := range remainS.Values {
		diags = append(diags, &hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Unsupported attribute",
			Detail:   fmt.Sprintf("An attribute named %q is not expected here.", name),
			Subject:  b.synthRange().Ptr(),
		})
	}
	return content, diags
}

func (b synthBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
	var diags hcl.Diagnostics
	content := &hcl.BodyContent{
		Attributes:       make(hcl.Attributes),
		MissingItemRange: b.synthRange(),
	}

	remainValues := make(map[string]cty.Value)
	for attrName, val := range b.Values {
		remainValues[attrName] = val
	}

	for _, attrS := range schema.Attributes {
		delete(remainValues, attrS.Name)
		val, defined := b.Values[attrS.Name]
		if !defined {
			if attrS.Required {
				diags = append(diags, &hcl.Diagnostic{
					Severity: hcl.DiagError,
					Summary:  "Missing required attribute",
					Detail:   fmt.Sprintf("The attribute %q is required, but no definition was found.", attrS.Name),
					Subject:  b.synthRange().Ptr(),
				})
			}
			continue
		}
		content.Attributes[attrS.Name] = b.synthAttribute(attrS.Name, val)
	}

	// We just ignore blocks altogether, because this body type never has
	// nested blocks.

	remain := synthBody{
		Filename: b.Filename,
		Values:   remainValues,
	}

	return content, remain, diags
}

func (b synthBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
	ret := make(hcl.Attributes)
	for name, val := range b.Values {
		ret[name] = b.synthAttribute(name, val)
	}
	return ret, nil
}

func (b synthBody) MissingItemRange() hcl.Range {
	return b.synthRange()
}

func (b synthBody) synthAttribute(name string, val cty.Value) *hcl.Attribute {
	rng := b.synthRange()
	return &hcl.Attribute{
		Name: name,
		Expr: &hclsyntax.LiteralValueExpr{
			Val:      val,
			SrcRange: rng,
		},
		NameRange: rng,
		Range:     rng,
	}
}

func (b synthBody) synthRange() hcl.Range {
	return hcl.Range{
		Filename: b.Filename,
		Start:    hcl.Pos{Line: 1, Column: 1},
		End:      hcl.Pos{Line: 1, Column: 1},
	}
}
