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

package globalref

import (
	"sort"

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

// ContributingResources analyzes all of the given references and
// for each one tries to walk backwards through any named values to find all
// resources whose values contributed either directly or indirectly to any of
// them.
//
// This is a wrapper around ContributingResourceReferences which simplifies
// the result to only include distinct resource addresses, not full references.
// If the configuration includes several different references to different
// parts of a resource, ContributingResources will not preserve that detail.
func (a *Analyzer) ContributingResources(refs ...Reference) []addrs.AbsResource {
	retRefs := a.ContributingResourceReferences(refs...)
	if len(retRefs) == 0 {
		return nil
	}

	uniq := make(map[string]addrs.AbsResource, len(refs))
	for _, ref := range retRefs {
		if addr, ok := resourceForAddr(ref.LocalRef.Subject); ok {
			moduleAddr := ref.ModuleAddr()
			absAddr := addr.Absolute(moduleAddr)
			uniq[absAddr.String()] = absAddr
		}
	}
	ret := make([]addrs.AbsResource, 0, len(uniq))
	for _, addr := range uniq {
		ret = append(ret, addr)
	}
	sort.Slice(ret, func(i, j int) bool {
		// We only have a sorting function for resource _instances_, but
		// it'll do well enough if we just pretend we have no-key instances.
		return ret[i].Instance(addrs.NoKey).Less(ret[j].Instance(addrs.NoKey))
	})
	return ret
}

// ContributingResourceReferences analyzes all of the given references and
// for each one tries to walk backwards through any named values to find all
// references to resource attributes that contributed either directly or
// indirectly to any of them.
//
// This is a global operation that can be potentially quite expensive for
// complex configurations.
func (a *Analyzer) ContributingResourceReferences(refs ...Reference) []Reference {
	// Our methodology here is to keep digging through MetaReferences
	// until we've visited everything we encounter directly or indirectly,
	// and keep track of any resources we find along the way.

	// We'll aggregate our result here, using the string representations of
	// the resources as keys to avoid returning the same one more than once.
	found := make(map[referenceAddrKey]Reference)

	// We might encounter the same object multiple times as we walk,
	// but we won't learn anything more by traversing them again and so we'll
	// just skip them instead.
	visitedObjects := make(map[referenceAddrKey]struct{})

	// A queue of objects we still need to visit.
	// Note that if we find multiple references to the same object then we'll
	// just arbitrary choose any one of them, because for our purposes here
	// it's immaterial which reference we actually followed.
	pendingObjects := make(map[referenceAddrKey]Reference)

	// Initial state: identify any directly-mentioned resources and
	// queue up any named values we refer to.
	for _, ref := range refs {
		if _, ok := resourceForAddr(ref.LocalRef.Subject); ok {
			found[ref.addrKey()] = ref
		}
		pendingObjects[ref.addrKey()] = ref
	}

	for len(pendingObjects) > 0 {
		// Note: we modify this map while we're iterating over it, which means
		// that anything we add might be either visited within a later
		// iteration of the inner loop or in a later iteration of the outer
		// loop, but we get the correct result either way because we keep
		// working until we've fully depleted the queue.
		for key, ref := range pendingObjects {
			delete(pendingObjects, key)

			// We do this _before_ the visit below just in case this is an
			// invalid config with a self-referential local value, in which
			// case we'll just silently ignore the self reference for our
			// purposes here, and thus still eventually converge (albeit
			// with an incomplete answer).
			visitedObjects[key] = struct{}{}

			moreRefs := a.MetaReferences(ref)
			for _, newRef := range moreRefs {
				if _, ok := resourceForAddr(newRef.LocalRef.Subject); ok {
					found[newRef.addrKey()] = newRef
				}

				newKey := newRef.addrKey()
				if _, visited := visitedObjects[newKey]; !visited {
					pendingObjects[newKey] = newRef
				}
			}
		}
	}

	if len(found) == 0 {
		return nil
	}

	ret := make([]Reference, 0, len(found))
	for _, ref := range found {
		ret = append(ret, ref)
	}
	return ret
}

func resourceForAddr(addr addrs.Referenceable) (addrs.Resource, bool) {
	switch addr := addr.(type) {
	case addrs.Resource:
		return addr, true
	case addrs.ResourceInstance:
		return addr.Resource, true
	default:
		return addrs.Resource{}, false
	}
}
