// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package stackaddrs

import (
	"fmt"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/hclsyntax"

	"github.com/hashicorp/terraform/internal/addrs"
	"github.com/hashicorp/terraform/internal/collections"
	"github.com/hashicorp/terraform/internal/tfdiags"
)

// Component is the address of a "component" block within a stack config.
type Component struct {
	Name string
}

func (Component) referenceableSigil()   {}
func (Component) inStackConfigSigil()   {}
func (Component) inStackInstanceSigil() {}

func (c Component) String() string {
	return "component." + c.Name
}

func (c Component) UniqueKey() collections.UniqueKey[Component] {
	return c
}

// A Component is its own [collections.UniqueKey].
func (Component) IsUniqueKey(Component) {}

// ConfigComponent places a [Component] in the context of a particular [Stack].
type ConfigComponent = InStackConfig[Component]

// AbsComponent places a [Component] in the context of a particular [StackInstance].
type AbsComponent = InStackInstance[Component]

func AbsComponentToInstance(ist AbsComponent, ik addrs.InstanceKey) AbsComponentInstance {
	return AbsComponentInstance{
		Stack: ist.Stack,
		Item: ComponentInstance{
			Component: ist.Item,
			Key:       ik,
		},
	}
}

// ComponentInstance is the address of a dynamic instance of a component.
type ComponentInstance struct {
	Component Component
	Key       addrs.InstanceKey
}

func (ComponentInstance) inStackConfigSigil()   {}
func (ComponentInstance) inStackInstanceSigil() {}

func (c ComponentInstance) String() string {
	if c.Key == nil {
		return c.Component.String()
	}
	return c.Component.String() + c.Key.String()
}

func (c ComponentInstance) UniqueKey() collections.UniqueKey[ComponentInstance] {
	return c
}

// A ComponentInstance is its own [collections.UniqueKey].
func (ComponentInstance) IsUniqueKey(ComponentInstance) {}

// ConfigComponentInstance places a [ComponentInstance] in the context of a
// particular [Stack].
type ConfigComponentInstance = InStackConfig[ComponentInstance]

// AbsComponentInstance places a [ComponentInstance] in the context of a
// particular [StackInstance].
type AbsComponentInstance = InStackInstance[ComponentInstance]

func ConfigComponentForAbsInstance(instAddr AbsComponentInstance) ConfigComponent {
	configInst := ConfigForAbs(instAddr) // a ConfigComponentInstance
	return ConfigComponent{
		Stack: configInst.Stack,
		Item: Component{
			Name: configInst.Item.Component.Name,
		},
	}
}

func ParseAbsComponentInstance(traversal hcl.Traversal) (AbsComponentInstance, tfdiags.Diagnostics) {
	inst, remain, diags := ParseAbsComponentInstanceOnly(traversal)
	if diags.HasErrors() {
		return AbsComponentInstance{}, diags
	}

	if len(remain) > 0 {
		// Then we have some remaining traversal steps that weren't consumed
		// by the component instance address itself, which is an error when the
		// caller is using this function.
		rng := remain.SourceRange()
		// if "remain" is empty then the source range would be zero length,
		// and so we'll use the original traversal instead.
		if len(remain) == 0 {
			rng = traversal.SourceRange()
		}
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Invalid component instance address",
			Detail:   "The component instance address must include the keyword \"component\" followed by a component name.",
			Subject:  &rng,
		})
		return AbsComponentInstance{}, diags
	}

	return inst, diags
}

func ParseAbsComponentInstanceStr(s string) (AbsComponentInstance, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics
	traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(s), "", hcl.InitialPos)
	diags = diags.Append(hclDiags)
	if diags.HasErrors() {
		return AbsComponentInstance{}, diags
	}

	ret, moreDiags := ParseAbsComponentInstance(traversal)
	diags = diags.Append(moreDiags)
	return ret, diags
}

func ParsePartialComponentInstanceStr(s string) (AbsComponentInstance, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics
	traversal, hclDiags := hclsyntax.ParseTraversalPartial([]byte(s), "", hcl.InitialPos)
	diags = diags.Append(hclDiags)
	if diags.HasErrors() {
		return AbsComponentInstance{}, diags
	}

	ret, moreDiags := ParseAbsComponentInstance(traversal)
	diags = diags.Append(moreDiags)
	return ret, diags
}

func ParseAbsComponentInstanceStrOnly(s string) (AbsComponentInstance, hcl.Traversal, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics
	traversal, hclDiags := hclsyntax.ParseTraversalPartial([]byte(s), "", hcl.InitialPos)
	diags = diags.Append(hclDiags)
	if diags.HasErrors() {
		return AbsComponentInstance{}, traversal, diags
	}

	ret, rest, moreDiags := ParseAbsComponentInstanceOnly(traversal)
	diags = diags.Append(moreDiags)
	return ret, rest, diags
}

func ParseAbsComponentInstanceOnly(traversal hcl.Traversal) (AbsComponentInstance, hcl.Traversal, tfdiags.Diagnostics) {
	if traversal.IsRelative() {
		// This is always a caller bug: caller must only pass absolute
		// traversals in here.
		panic("ParseAbsComponentInstanceOnly with relative traversal")
	}

	stackInst, remain, diags := parseInStackInstancePrefix(traversal)
	if diags.HasErrors() {
		return AbsComponentInstance{}, remain, diags
	}

	// "remain" should now be the keyword "component" followed by a valid
	// component name, optionally followed by an instance key.
	const diagSummary = "Invalid component instance address"

	if kwStep, ok := remain[0].(hcl.TraverseAttr); !ok || kwStep.Name != "component" {
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  diagSummary,
			Detail:   "The component instance address must include the keyword \"component\" followed by a component name.",
			Subject:  remain[0].SourceRange().Ptr(),
		})
		return AbsComponentInstance{}, remain, diags
	}
	remain = remain[1:]

	nameStep, ok := remain[0].(hcl.TraverseAttr)
	if !ok {
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  diagSummary,
			Detail:   "The component instance address must include the keyword \"component\" followed by a component name.",
			Subject:  remain[1].SourceRange().Ptr(),
		})
		return AbsComponentInstance{}, remain, diags
	}
	remain = remain[1:]
	componentAddr := ComponentInstance{
		Component: Component{Name: nameStep.Name},
	}

	if len(remain) > 0 {
		switch instStep := remain[0].(type) {
		case hcl.TraverseIndex:
			var err error
			componentAddr.Key, err = addrs.ParseInstanceKey(instStep.Key)
			if err != nil {
				diags = diags.Append(&hcl.Diagnostic{
					Severity: hcl.DiagError,
					Summary:  diagSummary,
					Detail:   fmt.Sprintf("Invalid instance key: %s.", err),
					Subject:  instStep.SourceRange().Ptr(),
				})
				return AbsComponentInstance{}, remain, diags
			}

			remain = remain[1:]
		case hcl.TraverseSplat:
			componentAddr.Key = addrs.WildcardKey
			remain = remain[1:]
		}
	}

	return AbsComponentInstance{
		Stack: stackInst,
		Item:  componentAddr,
	}, remain, diags
}
